628 lines
18 KiB
JavaScript
628 lines
18 KiB
JavaScript
import React, { useState, useEffect } from "react";
|
|
import {
|
|
makeStyles,
|
|
Paper,
|
|
Grid,
|
|
FormControl,
|
|
InputLabel,
|
|
MenuItem,
|
|
TextField,
|
|
Table,
|
|
TableHead,
|
|
TableBody,
|
|
TableCell,
|
|
TableRow,
|
|
IconButton,
|
|
Select,
|
|
} from "@material-ui/core";
|
|
import { Formik, Form, Field } from "formik";
|
|
import ButtonWithSpinner from "../ButtonWithSpinner";
|
|
import ConfirmationModal from "../ConfirmationModal";
|
|
|
|
import { Edit as EditIcon } from "@material-ui/icons";
|
|
|
|
import { toast } from "react-toastify";
|
|
import useCompanies from "../../hooks/useCompanies";
|
|
import usePlans from "../../hooks/usePlans";
|
|
import ModalUsers from "../ModalUsers";
|
|
import api from "../../services/api";
|
|
import { head, isArray, has } from "lodash";
|
|
import { useDate } from "../../hooks/useDate";
|
|
|
|
import moment from "moment";
|
|
|
|
const useStyles = makeStyles((theme) => ({
|
|
root: {
|
|
width: "100%",
|
|
},
|
|
mainPaper: {
|
|
width: "100%",
|
|
flex: 1,
|
|
padding: theme.spacing(2),
|
|
},
|
|
fullWidth: {
|
|
width: "100%",
|
|
},
|
|
tableContainer: {
|
|
width: "100%",
|
|
overflowX: "scroll",
|
|
...theme.scrollbarStyles,
|
|
},
|
|
textfield: {
|
|
width: "100%",
|
|
},
|
|
textRight: {
|
|
textAlign: "right",
|
|
},
|
|
row: {
|
|
paddingTop: theme.spacing(2),
|
|
paddingBottom: theme.spacing(2),
|
|
},
|
|
control: {
|
|
paddingRight: theme.spacing(1),
|
|
paddingLeft: theme.spacing(1),
|
|
},
|
|
buttonContainer: {
|
|
textAlign: "right",
|
|
padding: theme.spacing(1),
|
|
},
|
|
}));
|
|
|
|
export function CompanyForm(props) {
|
|
const { onSubmit, onDelete, onCancel, initialValue, loading } = props;
|
|
const classes = useStyles();
|
|
const [plans, setPlans] = useState([]);
|
|
const [modalUser, setModalUser] = useState(false);
|
|
const [firstUser, setFirstUser] = useState({});
|
|
|
|
const [record, setRecord] = useState({
|
|
name: "",
|
|
email: "",
|
|
phone: "",
|
|
planId: "",
|
|
status: true,
|
|
campaignsEnabled: false,
|
|
dueDate: "",
|
|
recurrence: "",
|
|
...initialValue,
|
|
});
|
|
|
|
const { list: listPlans } = usePlans();
|
|
|
|
useEffect(() => {
|
|
async function fetchData() {
|
|
const list = await listPlans();
|
|
setPlans(list);
|
|
}
|
|
fetchData();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
setRecord((prev) => {
|
|
if (moment(initialValue).isValid()) {
|
|
initialValue.dueDate = moment(initialValue.dueDate).format(
|
|
"YYYY-MM-DD"
|
|
);
|
|
}
|
|
return {
|
|
...prev,
|
|
...initialValue,
|
|
};
|
|
});
|
|
}, [initialValue]);
|
|
|
|
const handleSubmit = async (data) => {
|
|
if (data.dueDate === "" || moment(data.dueDate).isValid() === false) {
|
|
data.dueDate = null;
|
|
}
|
|
onSubmit(data);
|
|
setRecord({ ...initialValue, dueDate: "" });
|
|
};
|
|
|
|
const handleOpenModalUsers = async () => {
|
|
try {
|
|
const { data } = await api.get("/users/list", {
|
|
params: {
|
|
companyId: initialValue.id,
|
|
},
|
|
});
|
|
if (isArray(data) && data.length) {
|
|
setFirstUser(head(data));
|
|
}
|
|
setModalUser(true);
|
|
} catch (e) {
|
|
toast.error(e);
|
|
}
|
|
};
|
|
|
|
const handleCloseModalUsers = () => {
|
|
setFirstUser({});
|
|
setModalUser(false);
|
|
};
|
|
|
|
const incrementDueDate = () => {
|
|
const data = { ...record };
|
|
if (data.dueDate !== "" && data.dueDate !== null) {
|
|
switch (data.recurrence) {
|
|
case "MENSAL":
|
|
data.dueDate = moment(data.dueDate)
|
|
.add(1, "month")
|
|
.format("YYYY-MM-DD");
|
|
break;
|
|
case "BIMESTRAL":
|
|
data.dueDate = moment(data.dueDate)
|
|
.add(2, "month")
|
|
.format("YYYY-MM-DD");
|
|
break;
|
|
case "TRIMESTRAL":
|
|
data.dueDate = moment(data.dueDate)
|
|
.add(3, "month")
|
|
.format("YYYY-MM-DD");
|
|
break;
|
|
case "SEMESTRAL":
|
|
data.dueDate = moment(data.dueDate)
|
|
.add(6, "month")
|
|
.format("YYYY-MM-DD");
|
|
break;
|
|
case "ANUAL":
|
|
data.dueDate = moment(data.dueDate)
|
|
.add(12, "month")
|
|
.format("YYYY-MM-DD");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
setRecord(data);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<ModalUsers
|
|
userId={firstUser.id}
|
|
companyId={initialValue.id}
|
|
open={modalUser}
|
|
onClose={handleCloseModalUsers}
|
|
/>
|
|
<Formik
|
|
enableReinitialize
|
|
className={classes.fullWidth}
|
|
initialValues={record}
|
|
onSubmit={(values, { resetForm }) =>
|
|
setTimeout(() => {
|
|
handleSubmit(values);
|
|
resetForm();
|
|
}, 500)
|
|
}
|
|
>
|
|
{(values, setValues) => (
|
|
<Form className={classes.fullWidth}>
|
|
<Grid spacing={2} justifyContent="flex-end" container>
|
|
<Grid xs={12} sm={6} md={4} item>
|
|
<Field
|
|
as={TextField}
|
|
label="Nome"
|
|
name="name"
|
|
variant="outlined"
|
|
className={classes.fullWidth}
|
|
margin="dense"
|
|
/>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<Field
|
|
as={TextField}
|
|
label="E-mail"
|
|
name="email"
|
|
variant="outlined"
|
|
className={classes.fullWidth}
|
|
margin="dense"
|
|
required
|
|
/>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<Field
|
|
as={TextField}
|
|
label="Telefone"
|
|
name="phone"
|
|
variant="outlined"
|
|
className={classes.fullWidth}
|
|
margin="dense"
|
|
/>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<FormControl margin="dense" variant="outlined" fullWidth>
|
|
<InputLabel htmlFor="plan-selection">Plano</InputLabel>
|
|
<Field
|
|
as={Select}
|
|
id="plan-selection"
|
|
label="Plano"
|
|
labelId="plan-selection-label"
|
|
name="planId"
|
|
margin="dense"
|
|
required
|
|
>
|
|
{plans.map((plan, key) => (
|
|
<MenuItem key={key} value={plan.id}>
|
|
{plan.name}
|
|
</MenuItem>
|
|
))}
|
|
</Field>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<FormControl margin="dense" variant="outlined" fullWidth>
|
|
<InputLabel htmlFor="status-selection">Status</InputLabel>
|
|
<Field
|
|
as={Select}
|
|
id="status-selection"
|
|
label="Status"
|
|
labelId="status-selection-label"
|
|
name="status"
|
|
margin="dense"
|
|
>
|
|
<MenuItem value={true}>Sim</MenuItem>
|
|
<MenuItem value={false}>Não</MenuItem>
|
|
</Field>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<FormControl margin="dense" variant="outlined" fullWidth>
|
|
<InputLabel htmlFor="status-selection">Campanhas</InputLabel>
|
|
<Field
|
|
as={Select}
|
|
id="campaigns-selection"
|
|
label="Campanhas"
|
|
labelId="campaigns-selection-label"
|
|
name="campaignsEnabled"
|
|
margin="dense"
|
|
>
|
|
<MenuItem value={true}>Habilitadas</MenuItem>
|
|
<MenuItem value={false}>Desabilitadas</MenuItem>
|
|
</Field>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<FormControl variant="outlined" fullWidth>
|
|
<Field
|
|
as={TextField}
|
|
label="Data de Vencimento"
|
|
type="date"
|
|
name="dueDate"
|
|
InputLabelProps={{
|
|
shrink: true,
|
|
}}
|
|
variant="outlined"
|
|
fullWidth
|
|
margin="dense"
|
|
/>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid xs={12} sm={6} md={2} item>
|
|
<FormControl margin="dense" variant="outlined" fullWidth>
|
|
<InputLabel htmlFor="recorrencia-selection">
|
|
Recorrência
|
|
</InputLabel>
|
|
<Field
|
|
as={Select}
|
|
label="Recorrência"
|
|
labelId="recorrencia-selection-label"
|
|
id="recurrence"
|
|
name="recurrence"
|
|
margin="dense"
|
|
>
|
|
<MenuItem value="MENSAL">Mensal</MenuItem>
|
|
{/*<MenuItem value="BIMESTRAL">Bimestral</MenuItem>*/}
|
|
{/*<MenuItem value="TRIMESTRAL">Trimestral</MenuItem>*/}
|
|
{/*<MenuItem value="SEMESTRAL">Semestral</MenuItem>*/}
|
|
{/*<MenuItem value="ANUAL">Anual</MenuItem>*/}
|
|
</Field>
|
|
</FormControl>
|
|
</Grid>
|
|
<Grid xs={12} item>
|
|
<Grid justifyContent="flex-end" spacing={1} container>
|
|
<Grid xs={4} md={1} item>
|
|
<ButtonWithSpinner
|
|
className={classes.fullWidth}
|
|
style={{ marginTop: 7 }}
|
|
loading={loading}
|
|
onClick={() => onCancel()}
|
|
variant="contained"
|
|
>
|
|
Limpar
|
|
</ButtonWithSpinner>
|
|
</Grid>
|
|
{record.id !== undefined ? (
|
|
<>
|
|
<Grid xs={6} md={1} item>
|
|
<ButtonWithSpinner
|
|
style={{ marginTop: 7 }}
|
|
className={classes.fullWidth}
|
|
loading={loading}
|
|
onClick={() => onDelete(record)}
|
|
variant="contained"
|
|
color="secondary"
|
|
>
|
|
Excluir
|
|
</ButtonWithSpinner>
|
|
</Grid>
|
|
<Grid xs={6} md={2} item>
|
|
<ButtonWithSpinner
|
|
style={{ marginTop: 7 }}
|
|
className={classes.fullWidth}
|
|
loading={loading}
|
|
onClick={() => incrementDueDate()}
|
|
variant="contained"
|
|
color="primary"
|
|
>
|
|
+ Vencimento
|
|
</ButtonWithSpinner>
|
|
</Grid>
|
|
<Grid xs={6} md={1} item>
|
|
<ButtonWithSpinner
|
|
style={{ marginTop: 7 }}
|
|
className={classes.fullWidth}
|
|
loading={loading}
|
|
onClick={() => handleOpenModalUsers()}
|
|
variant="contained"
|
|
color="primary"
|
|
>
|
|
Usuário
|
|
</ButtonWithSpinner>
|
|
</Grid>
|
|
</>
|
|
) : null}
|
|
<Grid xs={6} md={1} item>
|
|
<ButtonWithSpinner
|
|
className={classes.fullWidth}
|
|
style={{ marginTop: 7 }}
|
|
loading={loading}
|
|
type="submit"
|
|
variant="contained"
|
|
color="primary"
|
|
>
|
|
Salvar
|
|
</ButtonWithSpinner>
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</Grid>
|
|
</Form>
|
|
)}
|
|
</Formik>
|
|
</>
|
|
);
|
|
}
|
|
|
|
export function CompaniesManagerGrid(props) {
|
|
const { records, onSelect } = props;
|
|
const classes = useStyles();
|
|
const { dateToClient } = useDate();
|
|
|
|
const renderStatus = (row) => {
|
|
return row.status === false ? "Não" : "Sim";
|
|
};
|
|
|
|
const renderPlan = (row) => {
|
|
return row.planId !== null ? row.plan.name : "-";
|
|
};
|
|
|
|
const renderCampaignsStatus = (row) => {
|
|
if (
|
|
has(row, "settings") &&
|
|
isArray(row.settings) &&
|
|
row.settings.length > 0
|
|
) {
|
|
const setting = row.settings.find((s) => s.key === "campaignsEnabled");
|
|
if (setting) {
|
|
return setting.value === "true" ? "Habilitadas" : "Desabilitadas";
|
|
}
|
|
}
|
|
return "Desabilitadas";
|
|
};
|
|
|
|
const rowStyle = (record) => {
|
|
if (moment(record.dueDate).isValid()) {
|
|
const now = moment();
|
|
const dueDate = moment(record.dueDate);
|
|
const diff = dueDate.diff(now, "days");
|
|
if (diff === 5) {
|
|
return { backgroundColor: "#fffead" };
|
|
}
|
|
if (diff >= -3 && diff <= 4) {
|
|
return { backgroundColor: "#f7cc8f" };
|
|
}
|
|
if (diff === -4) {
|
|
return { backgroundColor: "#fa8c8c" };
|
|
}
|
|
}
|
|
return {};
|
|
};
|
|
|
|
return (
|
|
<Paper className={classes.tableContainer}>
|
|
<Table
|
|
className={classes.fullWidth}
|
|
size="small"
|
|
aria-label="a dense table"
|
|
>
|
|
<TableHead>
|
|
<TableRow>
|
|
<TableCell align="center" style={{ width: "1%" }}>
|
|
#
|
|
</TableCell>
|
|
<TableCell align="left">Nome</TableCell>
|
|
<TableCell align="left">E-mail</TableCell>
|
|
<TableCell align="left">Telefone</TableCell>
|
|
<TableCell align="left">Plano</TableCell>
|
|
<TableCell align="left">Campanhas</TableCell>
|
|
<TableCell align="left">Status</TableCell>
|
|
<TableCell align="left">Criada Em</TableCell>
|
|
<TableCell align="left">Vencimento</TableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
{records.map((row, key) => (
|
|
<TableRow style={rowStyle(row)} key={key}>
|
|
<TableCell align="center" style={{ width: "1%" }}>
|
|
<IconButton onClick={() => onSelect(row)} aria-label="delete">
|
|
<EditIcon />
|
|
</IconButton>
|
|
</TableCell>
|
|
<TableCell align="left">{row.name || "-"}</TableCell>
|
|
<TableCell align="left">{row.email || "-"}</TableCell>
|
|
<TableCell align="left">{row.phone || "-"}</TableCell>
|
|
<TableCell align="left">{renderPlan(row)}</TableCell>
|
|
<TableCell align="left">{renderCampaignsStatus(row)}</TableCell>
|
|
<TableCell align="left">{renderStatus(row)}</TableCell>
|
|
<TableCell align="left">{dateToClient(row.createdAt)}</TableCell>
|
|
<TableCell align="left">
|
|
{dateToClient(row.dueDate)}
|
|
<br />
|
|
<span>{row.recurrence}</span>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
</Paper>
|
|
);
|
|
}
|
|
|
|
export default function CompaniesManager() {
|
|
const classes = useStyles();
|
|
const { list, save, update, remove } = useCompanies();
|
|
|
|
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
const [records, setRecords] = useState([]);
|
|
const [record, setRecord] = useState({
|
|
name: "",
|
|
email: "",
|
|
phone: "",
|
|
planId: "",
|
|
status: true,
|
|
campaignsEnabled: false,
|
|
dueDate: "",
|
|
recurrence: "",
|
|
});
|
|
|
|
useEffect(() => {
|
|
loadPlans();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, []);
|
|
|
|
const loadPlans = async () => {
|
|
setLoading(true);
|
|
try {
|
|
const companyList = await list();
|
|
setRecords(companyList);
|
|
} catch (e) {
|
|
toast.error("Não foi possível carregar a lista de registros");
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const handleSubmit = async (data) => {
|
|
setLoading(true);
|
|
try {
|
|
if (data.id !== undefined) {
|
|
await update(data);
|
|
} else {
|
|
await save(data);
|
|
}
|
|
await loadPlans();
|
|
handleCancel();
|
|
toast.success("Operação realizada com sucesso!");
|
|
} catch (e) {
|
|
toast.error(
|
|
"Não foi possível realizar a operação. Verifique se já existe uma empresa com o mesmo nome ou se os campos foram preenchidos corretamente"
|
|
);
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const handleDelete = async () => {
|
|
setLoading(true);
|
|
try {
|
|
await remove(record.id);
|
|
await loadPlans();
|
|
handleCancel();
|
|
toast.success("Operação realizada com sucesso!");
|
|
} catch (e) {
|
|
toast.error("Não foi possível realizar a operação");
|
|
}
|
|
setLoading(false);
|
|
};
|
|
|
|
const handleOpenDeleteDialog = () => {
|
|
setShowConfirmDialog(true);
|
|
};
|
|
|
|
const handleCancel = () => {
|
|
setRecord((prev) => ({
|
|
...prev,
|
|
name: "",
|
|
email: "",
|
|
phone: "",
|
|
planId: "",
|
|
status: true,
|
|
campaignsEnabled: false,
|
|
dueDate: "",
|
|
recurrence: "",
|
|
}));
|
|
};
|
|
|
|
const handleSelect = (data) => {
|
|
let campaignsEnabled = false;
|
|
|
|
const setting = data.settings.find(
|
|
(s) => s.key.indexOf("campaignsEnabled") > -1
|
|
);
|
|
if (setting) {
|
|
campaignsEnabled =
|
|
setting.value === "true" || setting.value === "enabled";
|
|
}
|
|
|
|
setRecord((prev) => ({
|
|
...prev,
|
|
id: data.id,
|
|
name: data.name || "",
|
|
phone: data.phone || "",
|
|
email: data.email || "",
|
|
planId: data.planId || "",
|
|
status: data.status === false ? false : true,
|
|
campaignsEnabled,
|
|
dueDate: data.dueDate || "",
|
|
recurrence: data.recurrence || "",
|
|
}));
|
|
};
|
|
|
|
return (
|
|
<Paper className={classes.mainPaper} elevation={0}>
|
|
<Grid spacing={2} container>
|
|
<Grid xs={12} item>
|
|
<CompanyForm
|
|
initialValue={record}
|
|
onDelete={handleOpenDeleteDialog}
|
|
onSubmit={handleSubmit}
|
|
onCancel={handleCancel}
|
|
loading={loading}
|
|
/>
|
|
</Grid>
|
|
<Grid xs={12} item>
|
|
<CompaniesManagerGrid records={records} onSelect={handleSelect} />
|
|
</Grid>
|
|
</Grid>
|
|
<ConfirmationModal
|
|
title="Exclusão de Registro"
|
|
open={showConfirmDialog}
|
|
onClose={() => setShowConfirmDialog(false)}
|
|
onConfirm={() => handleDelete()}
|
|
>
|
|
Deseja realmente excluir esse registro?
|
|
</ConfirmationModal>
|
|
</Paper>
|
|
);
|
|
}
|