updante do modulo campanha em andamento
parent
1e0b8b9d29
commit
ff0d2c3630
|
@ -0,0 +1,346 @@
|
||||||
|
import React, { useState, useEffect, useContext, createContext } from 'react'
|
||||||
|
import * as Yup from 'yup'
|
||||||
|
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 {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Button,
|
||||||
|
DialogActions,
|
||||||
|
CircularProgress,
|
||||||
|
TextField,
|
||||||
|
Switch,
|
||||||
|
FormControlLabel,
|
||||||
|
} from '@material-ui/core'
|
||||||
|
|
||||||
|
import api from '../../services/api'
|
||||||
|
import { i18n } from '../../translate/i18n'
|
||||||
|
import toastError from '../../errors/toastError'
|
||||||
|
import QueueSelect from '../QueueSelect'
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme) => ({
|
||||||
|
root: {
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
},
|
||||||
|
|
||||||
|
multFieldLine: {
|
||||||
|
display: 'flex',
|
||||||
|
'& > *:not(:last-child)': {
|
||||||
|
marginRight: theme.spacing(1),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
btnWrapper: {
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
|
||||||
|
buttonProgress: {
|
||||||
|
color: green[500],
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
marginTop: -12,
|
||||||
|
marginLeft: -12,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
const SessionSchema = Yup.object().shape({
|
||||||
|
name: Yup.string()
|
||||||
|
.min(2, 'Too Short!')
|
||||||
|
.max(100, 'Too Long!')
|
||||||
|
.required('Required'),
|
||||||
|
})
|
||||||
|
|
||||||
|
const CampaignModal = ({ open, onClose, campaignId, dispatch }) => {
|
||||||
|
const classes = useStyles()
|
||||||
|
const initialState = {
|
||||||
|
name: '',
|
||||||
|
message: '',
|
||||||
|
whatsapp_sender: '',
|
||||||
|
csv_original_file_name: '',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { user } = useContext(AuthContext)
|
||||||
|
|
||||||
|
const { whatsApps } = useContext(WhatsAppsContext);
|
||||||
|
|
||||||
|
console.log('------------> whatsApps: ', whatsApps)
|
||||||
|
|
||||||
|
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 () => {
|
||||||
|
if (!campaignId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { data } = await apiBroker.get('/campaign', {
|
||||||
|
params: {
|
||||||
|
adminId: user.id,
|
||||||
|
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||||
|
identifier: 'campaign',
|
||||||
|
id: campaignId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setCampaign(data.campaign)
|
||||||
|
setSelectedNumber(data.campaign.whatsapp_sender)
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
toastError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchSession()
|
||||||
|
}, [campaignId])
|
||||||
|
|
||||||
|
const handleSaveCampaign = async (values) => {
|
||||||
|
let response = null
|
||||||
|
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('adminId', user.id)
|
||||||
|
formData.append('baseURL', process.env.REACT_APP_BACKEND_URL_PRIVATE)
|
||||||
|
formData.append('frontURL', process.env.REACT_APP_FRONTEND_URL)
|
||||||
|
formData.append('identifier', 'campaign')
|
||||||
|
formData.append('file', file)
|
||||||
|
formData.append('name', values.name)
|
||||||
|
formData.append('whatsapp_sender', selectedNumber)
|
||||||
|
formData.append('message', values.message)
|
||||||
|
formData.append('csv_original_file_name', file?.name)
|
||||||
|
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
headers: {
|
||||||
|
'content-type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (campaignId) {
|
||||||
|
|
||||||
|
response = await apiBroker.patch(`/campaign/${campaignId}`,
|
||||||
|
formData,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
toast.success('Campanha atualizada com sucesso!')
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
response = await apiBroker.post('/campaign',
|
||||||
|
formData,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
toast.success('Campanha criada com sucesso!')
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({ type: "UPDATE_CAMPAIGNS", payload: response.data.campaign })
|
||||||
|
|
||||||
|
handleClose()
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
toastError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
onClose()
|
||||||
|
setCampaign(initialState)
|
||||||
|
setSelectedNumber('')
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleChange(event) {
|
||||||
|
try {
|
||||||
|
if (event.target.files[0].size > 1024 * 1024 * 4) {
|
||||||
|
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
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
maxWidth="sm"
|
||||||
|
fullWidth
|
||||||
|
scroll="paper"
|
||||||
|
>
|
||||||
|
<DialogTitle>
|
||||||
|
{campaignId ? 'Editar campanha' : 'Adicionar campanha'}
|
||||||
|
</DialogTitle>
|
||||||
|
<Formik
|
||||||
|
initialValues={campaign}
|
||||||
|
enableReinitialize={true}
|
||||||
|
validationSchema={SessionSchema}
|
||||||
|
onSubmit={(values, actions) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleSaveCampaign(values)
|
||||||
|
actions.setSubmitting(false)
|
||||||
|
}, 400)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ values, touched, errors, isSubmitting }) => (
|
||||||
|
|
||||||
|
<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}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Select
|
||||||
|
value={selectedNumber}
|
||||||
|
onChange={(e) => setSelectedNumber(e.target.value)}
|
||||||
|
label={i18n.t("transferTicketModal.fieldQueuePlaceholder")}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<MenuItem style={{ background: "white", }} value={''}> </MenuItem>
|
||||||
|
{whatsApps.map((whatsapp) => (
|
||||||
|
<MenuItem
|
||||||
|
key={whatsapp.id}
|
||||||
|
value={whatsapp.number}
|
||||||
|
onMouseEnter={() => setItemHover(whatsapp.id)}
|
||||||
|
onMouseLeave={() => setItemHover(-1)}
|
||||||
|
>{whatsapp.number}
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={classes.multFieldLine}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<Field
|
||||||
|
as={TextField}
|
||||||
|
label="Mensagem"
|
||||||
|
type="message"
|
||||||
|
multiline
|
||||||
|
rows={5}
|
||||||
|
fullWidth
|
||||||
|
name="message"
|
||||||
|
error={touched.message && Boolean(errors.message)}
|
||||||
|
helperText={touched.message && errors.message}
|
||||||
|
variant="outlined"
|
||||||
|
margin="dense"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
gap: '10px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept=".csv"
|
||||||
|
style={{ display: 'none' }}
|
||||||
|
onChange={handleChange}
|
||||||
|
id="contained-button-file"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<label htmlFor="contained-button-file">
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
component="span"
|
||||||
|
>
|
||||||
|
CSV UPLOAD
|
||||||
|
</Button>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<h3>{file?.name || campaign?.csv_original_file_name}</h3>
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button
|
||||||
|
onClick={handleClose}
|
||||||
|
color="secondary"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
variant="outlined"
|
||||||
|
>
|
||||||
|
{i18n.t('whatsappModal.buttons.cancel')}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
color="primary"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
variant="contained"
|
||||||
|
className={classes.btnWrapper}
|
||||||
|
>
|
||||||
|
{campaignId
|
||||||
|
? i18n.t('whatsappModal.buttons.okEdit')
|
||||||
|
: i18n.t('whatsappModal.buttons.okAdd')}
|
||||||
|
{isSubmitting && (
|
||||||
|
<CircularProgress
|
||||||
|
size={24}
|
||||||
|
className={classes.buttonProgress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Form>
|
||||||
|
)}
|
||||||
|
</Formik>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(CampaignModal)
|
|
@ -1,40 +1,42 @@
|
||||||
import React, { useContext, useEffect, useState } from "react";
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from 'react-router-dom'
|
||||||
|
|
||||||
import ListItem from "@material-ui/core/ListItem";
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
import ListItemIcon from '@material-ui/core/ListItemIcon'
|
||||||
import ListItemText from "@material-ui/core/ListItemText";
|
import ListItemText from '@material-ui/core/ListItemText'
|
||||||
import ListSubheader from "@material-ui/core/ListSubheader";
|
import ListSubheader from '@material-ui/core/ListSubheader'
|
||||||
import Divider from "@material-ui/core/Divider";
|
import Divider from '@material-ui/core/Divider'
|
||||||
import { Badge } from "@material-ui/core";
|
import { Badge } from '@material-ui/core'
|
||||||
import DashboardOutlinedIcon from "@material-ui/icons/DashboardOutlined";
|
import DashboardOutlinedIcon from '@material-ui/icons/DashboardOutlined'
|
||||||
|
|
||||||
import ReportOutlinedIcon from "@material-ui/icons/ReportOutlined";
|
import ReportOutlinedIcon from '@material-ui/icons/ReportOutlined'
|
||||||
import SendOutlined from "@material-ui/icons/SendOutlined";
|
import SendOutlined from '@material-ui/icons/SendOutlined'
|
||||||
|
|
||||||
//import ReportOutlined from "@bit/mui-org.material-ui-icons.report-outlined";
|
//import ReportOutlined from "@bit/mui-org.material-ui-icons.report-outlined";
|
||||||
|
|
||||||
|
import WhatsAppIcon from '@material-ui/icons/WhatsApp'
|
||||||
|
import SyncAltIcon from '@material-ui/icons/SyncAlt'
|
||||||
|
import SettingsOutlinedIcon from '@material-ui/icons/SettingsOutlined'
|
||||||
|
import PeopleAltOutlinedIcon from '@material-ui/icons/PeopleAltOutlined'
|
||||||
|
import ContactPhoneOutlinedIcon from '@material-ui/icons/ContactPhoneOutlined'
|
||||||
|
import AccountTreeOutlinedIcon from '@material-ui/icons/AccountTreeOutlined'
|
||||||
|
import QuestionAnswerOutlinedIcon from '@material-ui/icons/QuestionAnswerOutlined'
|
||||||
|
|
||||||
import WhatsAppIcon from "@material-ui/icons/WhatsApp";
|
import { i18n } from '../translate/i18n'
|
||||||
import SyncAltIcon from "@material-ui/icons/SyncAlt";
|
import { WhatsAppsContext } from '../context/WhatsApp/WhatsAppsContext'
|
||||||
import SettingsOutlinedIcon from "@material-ui/icons/SettingsOutlined";
|
import { AuthContext } from '../context/Auth/AuthContext'
|
||||||
import PeopleAltOutlinedIcon from "@material-ui/icons/PeopleAltOutlined";
|
import { Can } from '../components/Can'
|
||||||
import ContactPhoneOutlinedIcon from "@material-ui/icons/ContactPhoneOutlined";
|
|
||||||
import AccountTreeOutlinedIcon from "@material-ui/icons/AccountTreeOutlined";
|
|
||||||
import QuestionAnswerOutlinedIcon from "@material-ui/icons/QuestionAnswerOutlined";
|
|
||||||
|
|
||||||
import { i18n } from "../translate/i18n";
|
|
||||||
import { WhatsAppsContext } from "../context/WhatsApp/WhatsAppsContext";
|
|
||||||
import { AuthContext } from "../context/Auth/AuthContext";
|
|
||||||
import { Can } from "../components/Can";
|
|
||||||
|
|
||||||
function ListItemLink(props) {
|
function ListItemLink(props) {
|
||||||
const { icon, primary, to, className } = props;
|
const { icon, primary, to, className } = props
|
||||||
|
|
||||||
const renderLink = React.useMemo(
|
const renderLink = React.useMemo(
|
||||||
() => React.forwardRef((itemProps, ref) => <RouterLink to={to} ref={ref} {...itemProps} />),
|
() =>
|
||||||
|
React.forwardRef((itemProps, ref) => (
|
||||||
|
<RouterLink to={to} ref={ref} {...itemProps} />
|
||||||
|
)),
|
||||||
[to]
|
[to]
|
||||||
);
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
|
@ -43,55 +45,59 @@ function ListItemLink(props) {
|
||||||
<ListItemText primary={primary} />
|
<ListItemText primary={primary} />
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</li>
|
</li>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const MainListItems = (props) => {
|
const MainListItems = (props) => {
|
||||||
const { setDrawerOpen } = props;
|
const { setDrawerOpen } = props
|
||||||
const { whatsApps } = useContext(WhatsAppsContext);
|
const { whatsApps } = useContext(WhatsAppsContext)
|
||||||
const { user } = useContext(AuthContext);
|
const { user } = useContext(AuthContext)
|
||||||
const [connectionWarning, setConnectionWarning] = useState(false);
|
const [connectionWarning, setConnectionWarning] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const delayDebounceFn = setTimeout(() => {
|
const delayDebounceFn = setTimeout(() => {
|
||||||
if (whatsApps.length > 0) {
|
if (whatsApps.length > 0) {
|
||||||
const offlineWhats = whatsApps.filter((whats) => {
|
const offlineWhats = whatsApps.filter((whats) => {
|
||||||
return (
|
return (
|
||||||
whats.status === "qrcode" ||
|
whats.status === 'qrcode' ||
|
||||||
whats.status === "PAIRING" ||
|
whats.status === 'PAIRING' ||
|
||||||
whats.status === "DISCONNECTED" ||
|
whats.status === 'DISCONNECTED' ||
|
||||||
whats.status === "TIMEOUT" ||
|
whats.status === 'TIMEOUT' ||
|
||||||
whats.status === "OPENING"
|
whats.status === 'OPENING'
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
if (offlineWhats.length > 0) {
|
if (offlineWhats.length > 0) {
|
||||||
setConnectionWarning(true);
|
setConnectionWarning(true)
|
||||||
} else {
|
} else {
|
||||||
setConnectionWarning(false);
|
setConnectionWarning(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 2000);
|
}, 2000)
|
||||||
return () => clearTimeout(delayDebounceFn);
|
return () => clearTimeout(delayDebounceFn)
|
||||||
}, [whatsApps]);
|
}, [whatsApps])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
//Solicitado pelo Adriano: Click no LinkItem e fechar o menu!
|
//Solicitado pelo Adriano: Click no LinkItem e fechar o menu!
|
||||||
<div onClick={() => setDrawerOpen(false)}>
|
<div onClick={() => setDrawerOpen(false)}>
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/tickets"
|
to="/tickets"
|
||||||
primary={i18n.t("mainDrawer.listItems.tickets")}
|
primary={i18n.t('mainDrawer.listItems.tickets')}
|
||||||
icon={<WhatsAppIcon />}
|
icon={<WhatsAppIcon />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/contacts"
|
to="/contacts"
|
||||||
primary={i18n.t("mainDrawer.listItems.contacts")}
|
primary={i18n.t('mainDrawer.listItems.contacts')}
|
||||||
icon={<ContactPhoneOutlinedIcon />}
|
icon={<ContactPhoneOutlinedIcon />}
|
||||||
/>
|
/>
|
||||||
<ListItemLink to="/schedulesReminder" primary={i18n.t("mainDrawer.listItems.schedules")} icon={<SendOutlined />} />
|
<ListItemLink
|
||||||
|
to="/schedulesReminder"
|
||||||
|
primary={i18n.t('mainDrawer.listItems.schedules')}
|
||||||
|
icon={<SendOutlined />}
|
||||||
|
/>
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/quickAnswers"
|
to="/quickAnswers"
|
||||||
primary={i18n.t("mainDrawer.listItems.quickAnswers")}
|
primary={i18n.t('mainDrawer.listItems.quickAnswers')}
|
||||||
icon={<QuestionAnswerOutlinedIcon />}
|
icon={<QuestionAnswerOutlinedIcon />}
|
||||||
/>
|
/>
|
||||||
<Can
|
<Can
|
||||||
|
@ -100,31 +106,47 @@ const MainListItems = (props) => {
|
||||||
yes={() => (
|
yes={() => (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<ListSubheader inset>{i18n.t("mainDrawer.listItems.administration")}</ListSubheader>
|
<ListSubheader inset>
|
||||||
|
{i18n.t('mainDrawer.listItems.administration')}
|
||||||
|
</ListSubheader>
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/users"
|
to="/users"
|
||||||
primary={i18n.t("mainDrawer.listItems.users")}
|
primary={i18n.t('mainDrawer.listItems.users')}
|
||||||
icon={<PeopleAltOutlinedIcon />}
|
icon={<PeopleAltOutlinedIcon />}
|
||||||
/>
|
/>
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/queues"
|
to="/queues"
|
||||||
primary={i18n.t("mainDrawer.listItems.queues")}
|
primary={i18n.t('mainDrawer.listItems.queues')}
|
||||||
icon={<AccountTreeOutlinedIcon />}
|
icon={<AccountTreeOutlinedIcon />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/connections"
|
to="/connections"
|
||||||
primary={i18n.t("mainDrawer.listItems.connections")}
|
primary={i18n.t('mainDrawer.listItems.connections')}
|
||||||
icon={
|
icon={
|
||||||
<Badge badgeContent={connectionWarning ? "!" : 0} color="error">
|
<Badge badgeContent={connectionWarning ? '!' : 0} color="error">
|
||||||
<SyncAltIcon />
|
<SyncAltIcon />
|
||||||
</Badge>
|
</Badge>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ListItemLink to="/" primary="Dashboard" icon={<DashboardOutlinedIcon />} />
|
<ListItemLink
|
||||||
|
to="/"
|
||||||
|
primary="Dashboard"
|
||||||
|
icon={<DashboardOutlinedIcon />}
|
||||||
|
/>
|
||||||
|
|
||||||
<ListItemLink to="/report" primary="Relatório" icon={<ReportOutlinedIcon />} />
|
<ListItemLink
|
||||||
|
to="/report"
|
||||||
|
primary="Relatório"
|
||||||
|
icon={<ReportOutlinedIcon />}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ListItemLink
|
||||||
|
to="/campaign"
|
||||||
|
primary="Campanha"
|
||||||
|
icon={<ReportOutlinedIcon />}
|
||||||
|
/>
|
||||||
|
|
||||||
<Can
|
<Can
|
||||||
role={user.profile}
|
role={user.profile}
|
||||||
|
@ -132,7 +154,7 @@ const MainListItems = (props) => {
|
||||||
yes={() => (
|
yes={() => (
|
||||||
<ListItemLink
|
<ListItemLink
|
||||||
to="/settings"
|
to="/settings"
|
||||||
primary={i18n.t("mainDrawer.listItems.settings")}
|
primary={i18n.t('mainDrawer.listItems.settings')}
|
||||||
icon={<SettingsOutlinedIcon />}
|
icon={<SettingsOutlinedIcon />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -141,7 +163,7 @@ const MainListItems = (props) => {
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default MainListItems;
|
export default MainListItems
|
||||||
|
|
|
@ -0,0 +1,696 @@
|
||||||
|
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) {
|
||||||
|
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: '',
|
||||||
|
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'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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') {
|
||||||
|
try {
|
||||||
|
await apiBroker.delete(`/campaign/${confirmModalInfo.campaignId}`, {
|
||||||
|
params: {
|
||||||
|
adminId: user.id,
|
||||||
|
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||||
|
identifier: 'campaign',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
dispatch({ type: "DELETE_CAMPAIGN", payload: confirmModalInfo.campaignId })
|
||||||
|
|
||||||
|
toast.success('Campanha deletada com sucesso')
|
||||||
|
} catch (err) {
|
||||||
|
toastError(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfirmModalInfo(confirmationModalInitialState)
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderActionButtons = (campaign) => {
|
||||||
|
return (
|
||||||
|
<Can
|
||||||
|
role={user.profile}
|
||||||
|
perform="connection-button:show"
|
||||||
|
yes={() => (
|
||||||
|
<>
|
||||||
|
{campaign.status === 'qrcode' && (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => handleOpenQrModal(campaign)}
|
||||||
|
>
|
||||||
|
{i18n.t('connections.buttons.qrcode')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{campaign.status === 'DISCONNECTED' && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
color="primary"
|
||||||
|
onClick={() => handleStartWhatsAppSession(campaign.id)}
|
||||||
|
>
|
||||||
|
{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')}
|
||||||
|
</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)
|
||||||
|
|
||||||
|
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">
|
||||||
|
Nome
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell align="center">
|
||||||
|
Status
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<Can
|
||||||
|
role={user.profile}
|
||||||
|
perform="connection-button:show"
|
||||||
|
yes={() => (
|
||||||
|
<TableCell align="center">
|
||||||
|
{i18n.t('connections.table.session')}
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TableCell align="center">
|
||||||
|
Whatsapp sender
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
|
||||||
|
<TableCell align="center">
|
||||||
|
Mensagem
|
||||||
|
</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">
|
||||||
|
Status
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<Can
|
||||||
|
role={user.profile}
|
||||||
|
perform="connection-button:show"
|
||||||
|
yes={() => (
|
||||||
|
<TableCell align="center">
|
||||||
|
{renderActionButtons(campaign)}
|
||||||
|
</TableCell>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TableCell align="center">
|
||||||
|
{campaign.whatsapp_sender}
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell align="center">
|
||||||
|
{campaign.message}
|
||||||
|
</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') ? (
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={() =>
|
||||||
|
handleEditCampaign(campaign)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Edit />
|
||||||
|
</IconButton>
|
||||||
|
) : (
|
||||||
|
<div></div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Can
|
||||||
|
role={user.profile}
|
||||||
|
perform="btn-remove-whatsapp"
|
||||||
|
yes={() => (
|
||||||
|
<IconButton
|
||||||
|
size="small"
|
||||||
|
onClick={(e) => {
|
||||||
|
handleOpenConfirmationModal(
|
||||||
|
'delete',
|
||||||
|
campaign.id
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DeleteOutline />
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</>
|
||||||
|
</Paper>
|
||||||
|
</MainContainer>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Campaign
|
|
@ -1,43 +1,43 @@
|
||||||
import React, { useState, useEffect, useReducer, useContext } from "react";
|
import React, { useState, useEffect, useReducer, useContext } from "react"
|
||||||
import openSocket from "socket.io-client";
|
import openSocket from "socket.io-client"
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify"
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom"
|
||||||
|
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles"
|
||||||
import Table from "@material-ui/core/Table";
|
import Table from "@material-ui/core/Table"
|
||||||
import TableBody from "@material-ui/core/TableBody";
|
import TableBody from "@material-ui/core/TableBody"
|
||||||
import TableCell from "@material-ui/core/TableCell";
|
import TableCell from "@material-ui/core/TableCell"
|
||||||
import TableHead from "@material-ui/core/TableHead";
|
import TableHead from "@material-ui/core/TableHead"
|
||||||
import TableRow from "@material-ui/core/TableRow";
|
import TableRow from "@material-ui/core/TableRow"
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper"
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button"
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@material-ui/core/Avatar"
|
||||||
import WhatsAppIcon from "@material-ui/icons/WhatsApp";
|
import WhatsAppIcon from "@material-ui/icons/WhatsApp"
|
||||||
import SearchIcon from "@material-ui/icons/Search";
|
import SearchIcon from "@material-ui/icons/Search"
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField"
|
||||||
import InputAdornment from "@material-ui/core/InputAdornment";
|
import InputAdornment from "@material-ui/core/InputAdornment"
|
||||||
|
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton"
|
||||||
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
|
import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline"
|
||||||
import EditIcon from "@material-ui/icons/Edit";
|
import EditIcon from "@material-ui/icons/Edit"
|
||||||
|
|
||||||
import api from "../../services/api";
|
import api from "../../services/api"
|
||||||
import TableRowSkeleton from "../../components/TableRowSkeleton";
|
import TableRowSkeleton from "../../components/TableRowSkeleton"
|
||||||
import ContactModal from "../../components/ContactModal";
|
import ContactModal from "../../components/ContactModal"
|
||||||
import ConfirmationModal from "../../components/ConfirmationModal/";
|
import ConfirmationModal from "../../components/ConfirmationModal/"
|
||||||
|
|
||||||
import { i18n } from "../../translate/i18n";
|
import { i18n } from "../../translate/i18n"
|
||||||
import MainHeader from "../../components/MainHeader";
|
import MainHeader from "../../components/MainHeader"
|
||||||
import Title from "../../components/Title";
|
import Title from "../../components/Title"
|
||||||
import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper";
|
import MainHeaderButtonsWrapper from "../../components/MainHeaderButtonsWrapper"
|
||||||
import MainContainer from "../../components/MainContainer";
|
import MainContainer from "../../components/MainContainer"
|
||||||
import toastError from "../../errors/toastError";
|
import toastError from "../../errors/toastError"
|
||||||
import { AuthContext } from "../../context/Auth/AuthContext";
|
import { AuthContext } from "../../context/Auth/AuthContext"
|
||||||
import { Can } from "../../components/Can";
|
import { Can } from "../../components/Can"
|
||||||
|
|
||||||
import apiBroker from "../../services/apiBroker";
|
import apiBroker from "../../services/apiBroker"
|
||||||
import fileDownload from 'js-file-download'
|
import fileDownload from 'js-file-download'
|
||||||
import ContactCreateTicketModal from "../../components/ContactCreateTicketModal";
|
import ContactCreateTicketModal from "../../components/ContactCreateTicketModal"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,50 +46,50 @@ const reducer = (state, action) => {
|
||||||
|
|
||||||
if (action.type === "LOAD_CONTACTS") {
|
if (action.type === "LOAD_CONTACTS") {
|
||||||
|
|
||||||
const contacts = action.payload;
|
const contacts = action.payload
|
||||||
const newContacts = [];
|
const newContacts = []
|
||||||
|
|
||||||
contacts.forEach((contact) => {
|
contacts.forEach((contact) => {
|
||||||
|
|
||||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id);
|
const contactIndex = state.findIndex((c) => +c.id === +contact.id)
|
||||||
|
|
||||||
if (contactIndex !== -1) {
|
if (contactIndex !== -1) {
|
||||||
state[contactIndex] = contact;
|
state[contactIndex] = contact
|
||||||
} else {
|
} else {
|
||||||
newContacts.push(contact);
|
newContacts.push(contact)
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
})
|
||||||
|
|
||||||
return [...state, ...newContacts];
|
return [...state, ...newContacts]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "UPDATE_CONTACTS") {
|
if (action.type === "UPDATE_CONTACTS") {
|
||||||
const contact = action.payload;
|
const contact = action.payload
|
||||||
const contactIndex = state.findIndex((c) => +c.id === +contact.id);
|
const contactIndex = state.findIndex((c) => +c.id === +contact.id)
|
||||||
|
|
||||||
if (contactIndex !== -1) {
|
if (contactIndex !== -1) {
|
||||||
state[contactIndex] = contact;
|
state[contactIndex] = contact
|
||||||
return [...state];
|
return [...state]
|
||||||
} else {
|
} else {
|
||||||
return [contact, ...state];
|
return [contact, ...state]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "DELETE_CONTACT") {
|
if (action.type === "DELETE_CONTACT") {
|
||||||
const contactId = action.payload;
|
const contactId = action.payload
|
||||||
|
|
||||||
const contactIndex = state.findIndex((c) => +c.id === +contactId);
|
const contactIndex = state.findIndex((c) => +c.id === +contactId)
|
||||||
if (contactIndex !== -1) {
|
if (contactIndex !== -1) {
|
||||||
state.splice(contactIndex, 1);
|
state.splice(contactIndex, 1)
|
||||||
}
|
}
|
||||||
return [...state];
|
return [...state]
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === "RESET") {
|
if (action.type === "RESET") {
|
||||||
return [];
|
return []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme) => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
mainPaper: {
|
mainPaper: {
|
||||||
|
@ -98,24 +98,24 @@ const useStyles = makeStyles((theme) => ({
|
||||||
overflowY: "scroll",
|
overflowY: "scroll",
|
||||||
...theme.scrollbarStyles,
|
...theme.scrollbarStyles,
|
||||||
},
|
},
|
||||||
}));
|
}))
|
||||||
|
|
||||||
const Contacts = () => {
|
const Contacts = () => {
|
||||||
const classes = useStyles();
|
const classes = useStyles()
|
||||||
const history = useHistory();
|
const history = useHistory()
|
||||||
|
|
||||||
const { user } = useContext(AuthContext);
|
const { user } = useContext(AuthContext)
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false)
|
||||||
const [pageNumber, setPageNumber] = useState(1);
|
const [pageNumber, setPageNumber] = useState(1)
|
||||||
const [searchParam, setSearchParam] = useState("");
|
const [searchParam, setSearchParam] = useState("")
|
||||||
const [contacts, dispatch] = useReducer(reducer, []);
|
const [contacts, dispatch] = useReducer(reducer, [])
|
||||||
const [selectedContactId, setSelectedContactId] = useState(null);
|
const [selectedContactId, setSelectedContactId] = useState(null)
|
||||||
const [contactModalOpen, setContactModalOpen] = useState(false);
|
const [contactModalOpen, setContactModalOpen] = useState(false)
|
||||||
const [isCreateTicketModalOpen, setIsCreateTicketModalOpen] = useState(false)
|
const [isCreateTicketModalOpen, setIsCreateTicketModalOpen] = useState(false)
|
||||||
const [deletingContact, setDeletingContact] = useState(null);
|
const [deletingContact, setDeletingContact] = useState(null)
|
||||||
const [confirmOpen, setConfirmOpen] = useState(false);
|
const [confirmOpen, setConfirmOpen] = useState(false)
|
||||||
const [hasMore, setHasMore] = useState(false);
|
const [hasMore, setHasMore] = useState(false)
|
||||||
|
|
||||||
|
|
||||||
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
const [onQueueStatus, setOnQueueProcessStatus] = useState(undefined)
|
||||||
|
@ -132,20 +132,20 @@ const Contacts = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData()
|
||||||
formData.append("adminId", user.id);
|
formData.append("adminId", user.id)
|
||||||
formData.append("baseURL", process.env.REACT_APP_BACKEND_URL_PRIVATE,);
|
formData.append("baseURL", process.env.REACT_APP_BACKEND_URL_PRIVATE,)
|
||||||
formData.append("frontURL", process.env.REACT_APP_FRONTEND_URL);
|
formData.append("frontURL", process.env.REACT_APP_FRONTEND_URL)
|
||||||
formData.append("identifier", 'contacts_insert_csv');
|
formData.append("identifier", 'contacts_insert_csv')
|
||||||
formData.append("file", event.target.files[0]);
|
formData.append("file", event.target.files[0])
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'multipart/form-data',
|
'content-type': 'multipart/form-data',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
const bulk_contact_insert = await apiBroker.post("/contacts/bulk/insert", formData, config);
|
const bulk_contact_insert = await apiBroker.post("/contacts/bulk/insert", formData, config)
|
||||||
|
|
||||||
console.log(bulk_contact_insert.data)
|
console.log(bulk_contact_insert.data)
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ const Contacts = () => {
|
||||||
|
|
||||||
// history.go(0);
|
// history.go(0);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ const Contacts = () => {
|
||||||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||||
identifier: 'contacts_insert_csv'
|
identifier: 'contacts_insert_csv'
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
if (insertOnQueue && insertOnQueue.data) {
|
if (insertOnQueue && insertOnQueue.data) {
|
||||||
|
|
||||||
|
@ -193,23 +193,23 @@ const Contacts = () => {
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
fetchReportOnQueue();
|
fetchReportOnQueue()
|
||||||
|
|
||||||
}, 500);
|
}, 500)
|
||||||
return () => clearTimeout(delayDebounceFn);
|
return () => clearTimeout(delayDebounceFn)
|
||||||
|
|
||||||
}, [user])
|
}, [user])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch({ type: "RESET" });
|
dispatch({ type: "RESET" })
|
||||||
setPageNumber(1);
|
setPageNumber(1)
|
||||||
}, [searchParam]);
|
}, [searchParam])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ const Contacts = () => {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true)
|
||||||
const delayDebounceFn = setTimeout(() => {
|
const delayDebounceFn = setTimeout(() => {
|
||||||
const fetchContacts = async () => {
|
const fetchContacts = async () => {
|
||||||
|
|
||||||
|
@ -230,25 +230,25 @@ const Contacts = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await api.get("/contacts/", { params: { searchParam, pageNumber }, });
|
const { data } = await api.get("/contacts/", { params: { searchParam, pageNumber }, })
|
||||||
|
|
||||||
|
|
||||||
dispatch({ type: "LOAD_CONTACTS", payload: data.contacts });
|
dispatch({ type: "LOAD_CONTACTS", payload: data.contacts })
|
||||||
setHasMore(data.hasMore);
|
setHasMore(data.hasMore)
|
||||||
setLoading(false);
|
setLoading(false)
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
}
|
||||||
fetchContacts();
|
fetchContacts()
|
||||||
}, 500);
|
}, 500)
|
||||||
return () => clearTimeout(delayDebounceFn);
|
return () => clearTimeout(delayDebounceFn)
|
||||||
}, [searchParam, pageNumber]);
|
}, [searchParam, pageNumber])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const socket = openSocket(process.env.REACT_APP_BACKEND_URL);
|
const socket = openSocket(process.env.REACT_APP_BACKEND_URL)
|
||||||
|
|
||||||
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
|
socket.on("contactsBulkInsertOnQueueStatus", (data) => {
|
||||||
if (data.action === 'update') {
|
if (data.action === 'update') {
|
||||||
|
@ -261,7 +261,7 @@ const Contacts = () => {
|
||||||
setOnQueueProcessStatus(data.insertOnQueue.queueStatus)
|
setOnQueueProcessStatus(data.insertOnQueue.queueStatus)
|
||||||
|
|
||||||
if (data.insertOnQueue.queueStatus === "success") {
|
if (data.insertOnQueue.queueStatus === "success") {
|
||||||
history.go(0);
|
history.go(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,18 +270,18 @@ const Contacts = () => {
|
||||||
|
|
||||||
socket.on("contact", (data) => {
|
socket.on("contact", (data) => {
|
||||||
if (data.action === "update" || data.action === "create") {
|
if (data.action === "update" || data.action === "create") {
|
||||||
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact });
|
dispatch({ type: "UPDATE_CONTACTS", payload: data.contact })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.action === "delete") {
|
if (data.action === "delete") {
|
||||||
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId });
|
dispatch({ type: "DELETE_CONTACT", payload: +data.contactId })
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
socket.disconnect();
|
socket.disconnect()
|
||||||
};
|
}
|
||||||
}, [user, history]);
|
}, [user, history])
|
||||||
|
|
||||||
const removeExtraSpace = (str) => {
|
const removeExtraSpace = (str) => {
|
||||||
|
|
||||||
|
@ -291,18 +291,18 @@ const Contacts = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSearch = (event) => {
|
const handleSearch = (event) => {
|
||||||
setSearchParam(removeExtraSpace(event.target.value.toLowerCase()));
|
setSearchParam(removeExtraSpace(event.target.value.toLowerCase()))
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleOpenContactModal = () => {
|
const handleOpenContactModal = () => {
|
||||||
setSelectedContactId(null);
|
setSelectedContactId(null)
|
||||||
setContactModalOpen(true);
|
setContactModalOpen(true)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleCloseContactModal = () => {
|
const handleCloseContactModal = () => {
|
||||||
setSelectedContactId(null);
|
setSelectedContactId(null)
|
||||||
setContactModalOpen(false);
|
setContactModalOpen(false)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleOpenCreateTicketModal = (contactId) => {
|
const handleOpenCreateTicketModal = (contactId) => {
|
||||||
setSelectedContactId(contactId)
|
setSelectedContactId(contactId)
|
||||||
|
@ -330,46 +330,46 @@ const Contacts = () => {
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const hadleEditContact = (contactId) => {
|
const hadleEditContact = (contactId) => {
|
||||||
setSelectedContactId(contactId);
|
setSelectedContactId(contactId)
|
||||||
setContactModalOpen(true);
|
setContactModalOpen(true)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleDeleteContact = async (contactId) => {
|
const handleDeleteContact = async (contactId) => {
|
||||||
try {
|
try {
|
||||||
await api.delete(`/contacts/${contactId}`);
|
await api.delete(`/contacts/${contactId}`)
|
||||||
toast.success(i18n.t("contacts.toasts.deleted"));
|
toast.success(i18n.t("contacts.toasts.deleted"))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err)
|
||||||
|
}
|
||||||
|
setDeletingContact(null)
|
||||||
|
setSearchParam("")
|
||||||
|
setPageNumber(1)
|
||||||
}
|
}
|
||||||
setDeletingContact(null);
|
|
||||||
setSearchParam("");
|
|
||||||
setPageNumber(1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleimportContact = async () => {
|
const handleimportContact = async () => {
|
||||||
try {
|
try {
|
||||||
await api.post("/contacts/import");
|
await api.post("/contacts/import")
|
||||||
history.go(0);
|
history.go(0)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
toastError(err);
|
toastError(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const loadMore = () => {
|
const loadMore = () => {
|
||||||
setPageNumber((prevState) => prevState + 1);
|
setPageNumber((prevState) => prevState + 1)
|
||||||
};
|
}
|
||||||
|
|
||||||
const handleScroll = (e) => {
|
const handleScroll = (e) => {
|
||||||
if (!hasMore || loading) return;
|
if (!hasMore || loading) return
|
||||||
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
|
const { scrollTop, scrollHeight, clientHeight } = e.currentTarget
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
if (scrollHeight - (scrollTop + 100) < clientHeight) {
|
||||||
loadMore();
|
loadMore()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const handleDownload = async () => {
|
const handleDownload = async () => {
|
||||||
|
@ -378,16 +378,16 @@ const Contacts = () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
let res = await apiBroker.get(`/contacts/download/${zipfile}`, { responseType: 'blob' });
|
let res = await apiBroker.get(`/contacts/download/${zipfile}`, { responseType: 'blob' })
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
fileDownload(res.data, `${zipfile}`);
|
fileDownload(res.data, `${zipfile}`)
|
||||||
setOnQueueProcessStatus('empty')
|
setOnQueueProcessStatus('empty')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ const Contacts = () => {
|
||||||
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
baseURL: process.env.REACT_APP_BACKEND_URL_PRIVATE,
|
||||||
identifier: 'contacts_insert_csv'
|
identifier: 'contacts_insert_csv'
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
setOnQueueProcessStatus('empty')
|
setOnQueueProcessStatus('empty')
|
||||||
|
@ -414,7 +414,7 @@ const Contacts = () => {
|
||||||
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -452,13 +452,13 @@ const Contacts = () => {
|
||||||
>
|
>
|
||||||
{"CSV ALL"}
|
{"CSV ALL"}
|
||||||
</Button> */}
|
</Button> */}
|
||||||
</>);
|
</>)
|
||||||
|
|
||||||
case 'pending' || 'processing':
|
case 'pending' || 'processing':
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>PROCESSING...</span>
|
<span>PROCESSING...</span>
|
||||||
</>);
|
</>)
|
||||||
|
|
||||||
case 'success':
|
case 'success':
|
||||||
return (
|
return (
|
||||||
|
@ -472,7 +472,7 @@ const Contacts = () => {
|
||||||
>
|
>
|
||||||
{'DOWNLOAD'}
|
{'DOWNLOAD'}
|
||||||
</Button>
|
</Button>
|
||||||
</>);
|
</>)
|
||||||
case 'error':
|
case 'error':
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -485,16 +485,16 @@ const Contacts = () => {
|
||||||
>
|
>
|
||||||
{'ERROR'}
|
{'ERROR'}
|
||||||
</Button>
|
</Button>
|
||||||
</>);
|
</>)
|
||||||
case 'downloading':
|
case 'downloading':
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>DOWNLOADING...</span>
|
<span>DOWNLOADING...</span>
|
||||||
</>);
|
</>)
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return (<><span>WAITING...</span></>);
|
return (<><span>WAITING...</span></>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,8 +642,8 @@ const Contacts = () => {
|
||||||
<IconButton
|
<IconButton
|
||||||
size="small"
|
size="small"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
setConfirmOpen(true);
|
setConfirmOpen(true)
|
||||||
setDeletingContact(contact);
|
setDeletingContact(contact)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DeleteOutlineIcon />
|
<DeleteOutlineIcon />
|
||||||
|
@ -659,7 +659,7 @@ const Contacts = () => {
|
||||||
</Table>
|
</Table>
|
||||||
</Paper>
|
</Paper>
|
||||||
</MainContainer>
|
</MainContainer>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Contacts;
|
export default Contacts
|
|
@ -1,27 +1,26 @@
|
||||||
import React from "react";
|
import React from 'react'
|
||||||
import { BrowserRouter, Switch } from "react-router-dom";
|
import { BrowserRouter, Switch } from 'react-router-dom'
|
||||||
import { ToastContainer } from "react-toastify";
|
import { ToastContainer } from 'react-toastify'
|
||||||
|
|
||||||
import LoggedInLayout from "../layout";
|
import LoggedInLayout from '../layout'
|
||||||
import Dashboard from "../pages/Dashboard/";
|
import Dashboard from '../pages/Dashboard/'
|
||||||
|
|
||||||
import Report from "../pages/Report/";
|
|
||||||
import SchedulesReminder from "../pages/SchedulesReminder/";
|
|
||||||
|
|
||||||
import Tickets from "../pages/Tickets/";
|
|
||||||
import Signup from "../pages/Signup/";
|
|
||||||
import Login from "../pages/Login/";
|
|
||||||
import Connections from "../pages/Connections/";
|
|
||||||
import Settings from "../pages/Settings/";
|
|
||||||
import Users from "../pages/Users";
|
|
||||||
import Contacts from "../pages/Contacts/";
|
|
||||||
import QuickAnswers from "../pages/QuickAnswers/";
|
|
||||||
import Queues from "../pages/Queues/";
|
|
||||||
import { AuthProvider } from "../context/Auth/AuthContext";
|
|
||||||
import { WhatsAppsProvider } from "../context/WhatsApp/WhatsAppsContext";
|
|
||||||
import Route from "./Route";
|
|
||||||
|
|
||||||
|
import Report from '../pages/Report/'
|
||||||
|
import SchedulesReminder from '../pages/SchedulesReminder/'
|
||||||
|
|
||||||
|
import Tickets from '../pages/Tickets/'
|
||||||
|
import Signup from '../pages/Signup/'
|
||||||
|
import Login from '../pages/Login/'
|
||||||
|
import Connections from '../pages/Connections/'
|
||||||
|
import Campaign from '../pages/Campaign'
|
||||||
|
import Settings from '../pages/Settings/'
|
||||||
|
import Users from '../pages/Users'
|
||||||
|
import Contacts from '../pages/Contacts/'
|
||||||
|
import QuickAnswers from '../pages/QuickAnswers/'
|
||||||
|
import Queues from '../pages/Queues/'
|
||||||
|
import { AuthProvider } from '../context/Auth/AuthContext'
|
||||||
|
import { WhatsAppsProvider } from '../context/WhatsApp/WhatsAppsContext'
|
||||||
|
import Route from './Route'
|
||||||
|
|
||||||
const Routes = () => {
|
const Routes = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -33,27 +32,48 @@ const Routes = () => {
|
||||||
<WhatsAppsProvider>
|
<WhatsAppsProvider>
|
||||||
<LoggedInLayout>
|
<LoggedInLayout>
|
||||||
<Route exact path="/" component={Dashboard} isPrivate />
|
<Route exact path="/" component={Dashboard} isPrivate />
|
||||||
<Route exact path="/tickets/:ticketId?" component={Tickets} isPrivate />
|
<Route
|
||||||
|
exact
|
||||||
|
path="/tickets/:ticketId?"
|
||||||
|
component={Tickets}
|
||||||
|
isPrivate
|
||||||
|
/>
|
||||||
|
|
||||||
<Route exact path="/connections" component={Connections} isPrivate />
|
<Route
|
||||||
|
exact
|
||||||
|
path="/connections"
|
||||||
|
component={Connections}
|
||||||
|
isPrivate
|
||||||
|
/>
|
||||||
|
|
||||||
<Route exact path="/report" component={Report} isPrivate />
|
<Route exact path="/report" component={Report} isPrivate />
|
||||||
|
|
||||||
<Route exact path="/contacts" component={Contacts} isPrivate />
|
<Route exact path="/contacts" component={Contacts} isPrivate />
|
||||||
|
|
||||||
<Route exact path="/schedulesReminder" component={SchedulesReminder} isPrivate />
|
<Route
|
||||||
|
exact
|
||||||
|
path="/schedulesReminder"
|
||||||
|
component={SchedulesReminder}
|
||||||
|
isPrivate
|
||||||
|
/>
|
||||||
|
|
||||||
<Route exact path="/users" component={Users} isPrivate />
|
<Route exact path="/users" component={Users} isPrivate />
|
||||||
<Route exact path="/quickAnswers" component={QuickAnswers} isPrivate />
|
<Route
|
||||||
|
exact
|
||||||
|
path="/quickAnswers"
|
||||||
|
component={QuickAnswers}
|
||||||
|
isPrivate
|
||||||
|
/>
|
||||||
<Route exact path="/Settings" component={Settings} isPrivate />
|
<Route exact path="/Settings" component={Settings} isPrivate />
|
||||||
<Route exact path="/Queues" component={Queues} isPrivate />
|
<Route exact path="/Queues" component={Queues} isPrivate />
|
||||||
|
<Route exact path="/campaign" component={Campaign} isPrivate />
|
||||||
</LoggedInLayout>
|
</LoggedInLayout>
|
||||||
</WhatsAppsProvider>
|
</WhatsAppsProvider>
|
||||||
</Switch>
|
</Switch>
|
||||||
<ToastContainer autoClose={3000} />
|
<ToastContainer autoClose={3000} />
|
||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
export default Routes;
|
export default Routes
|
||||||
|
|
Loading…
Reference in New Issue