1
0

9 کامیت‌ها 47677751ba ... 5db8ef1241

نویسنده SHA1 پیام تاریخ
  hiesoftrd 5db8ef1241 actualizar 1 سال پیش
  hiesoftrd 47677751ba actualizar 1 سال پیش
  hiesoftrd da5e327625 actualizar 1 سال پیش
  hiesoftrd 320395a096 actualizar 1 سال پیش
  hiesoftrd 9a8d5cdd42 actualizar 1 سال پیش
  hiesoftrd 5233d8885e actualizar 1 سال پیش
  hiesoftrd 89c4727431 actualizar 1 سال پیش
  hiesoftrd 6447a45524 actualizar 1 سال پیش
  hiesoftrd 2275ade083 actualizar 1 سال پیش
100فایلهای تغییر یافته به همراه0 افزوده شده و 15104 حذف شده
  1. 0 119
      frontend/src/App.js
  2. BIN
      frontend/src/assets/chat_notify.mp3
  3. BIN
      frontend/src/assets/dialogflow.png
  4. BIN
      frontend/src/assets/logo.png
  5. BIN
      frontend/src/assets/n8n.png
  6. BIN
      frontend/src/assets/planilha.xlsx
  7. BIN
      frontend/src/assets/sound.mp3
  8. BIN
      frontend/src/assets/sound.ogg
  9. BIN
      frontend/src/assets/typebot.jpg
  10. BIN
      frontend/src/assets/wa-background-dark.png
  11. BIN
      frontend/src/assets/wa-background.png
  12. BIN
      frontend/src/assets/webhook.png
  13. 0 338
      frontend/src/components/AnnouncementModal/index.js
  14. 0 329
      frontend/src/components/AnnouncementsPopover/index.js
  15. 0 23
      frontend/src/components/BackdropLoading/index.js
  16. 0 35
      frontend/src/components/ButtonWithSpinner/index.js
  17. 0 634
      frontend/src/components/CampaignModal/index.js
  18. 0 39
      frontend/src/components/Can/index.js
  19. 0 175
      frontend/src/components/CheckoutPage/CheckoutPage.js
  20. 0 76
      frontend/src/components/CheckoutPage/CheckoutSuccess/CheckoutSuccess.js
  21. 0 2
      frontend/src/components/CheckoutPage/CheckoutSuccess/index.js
  22. 0 117
      frontend/src/components/CheckoutPage/CheckoutSuccess/style.js
  23. 0 75
      frontend/src/components/CheckoutPage/FormModel/checkoutFormModel.js
  24. 0 32
      frontend/src/components/CheckoutPage/FormModel/formInitialValues.js
  25. 0 29
      frontend/src/components/CheckoutPage/FormModel/validationSchema.js
  26. 0 134
      frontend/src/components/CheckoutPage/Forms/AddressForm.js
  27. 0 238
      frontend/src/components/CheckoutPage/Forms/PaymentForm.js
  28. 0 61
      frontend/src/components/CheckoutPage/ReviewOrder/PaymentDetails.js
  29. 0 33
      frontend/src/components/CheckoutPage/ReviewOrder/ProductDetails.js
  30. 0 20
      frontend/src/components/CheckoutPage/ReviewOrder/ReviewOrder.js
  31. 0 26
      frontend/src/components/CheckoutPage/ReviewOrder/ShippingDetails.js
  32. 0 2
      frontend/src/components/CheckoutPage/ReviewOrder/index.js
  33. 0 12
      frontend/src/components/CheckoutPage/ReviewOrder/styles.js
  34. 0 2
      frontend/src/components/CheckoutPage/index.js
  35. 0 23
      frontend/src/components/CheckoutPage/styles.js
  36. 0 85
      frontend/src/components/ColorPicker/index.js
  37. 0 634
      frontend/src/components/CompaniesManager/index.js
  38. 0 45
      frontend/src/components/ConfirmationModal/index.js
  39. 0 199
      frontend/src/components/ContactDrawer/index.js
  40. 0 50
      frontend/src/components/ContactDrawerSkeleton/index.js
  41. 0 187
      frontend/src/components/ContactForm/index.js
  42. 0 181
      frontend/src/components/ContactListDialog/index.js
  43. 0 242
      frontend/src/components/ContactListItemModal/index.js
  44. 0 103
      frontend/src/components/ContactListTable/index.js
  45. 0 300
      frontend/src/components/ContactModal/index.js
  46. 0 204
      frontend/src/components/ContactNotes/index.js
  47. 0 206
      frontend/src/components/ContactNotesDialog/index.js
  48. 0 64
      frontend/src/components/ContactNotesDialogListItem/index.js
  49. 0 26
      frontend/src/components/ContactTag/index.js
  50. 0 50
      frontend/src/components/CurrencyInput/index.js
  51. 0 70
      frontend/src/components/DarkMode/index.js
  52. 0 53
      frontend/src/components/Dashboard/CardCounter.js
  53. 0 89
      frontend/src/components/Dashboard/TableAttendantsStatus.js
  54. 0 34
      frontend/src/components/Dialog/index.js
  55. 0 350
      frontend/src/components/FileModal/index.js
  56. 0 38
      frontend/src/components/FormFields/CheckboxField.js
  57. 0 54
      frontend/src/components/FormFields/DatePickerField.js
  58. 0 26
      frontend/src/components/FormFields/InputField.js
  59. 0 48
      frontend/src/components/FormFields/SelectField.js
  60. 0 5
      frontend/src/components/FormFields/index.js
  61. 0 291
      frontend/src/components/HelpsManager/index.js
  62. 0 217
      frontend/src/components/ImportContactsModal/index.js
  63. 0 45
      frontend/src/components/LanguageControl/index.js
  64. 0 53
      frontend/src/components/LocationPreview/index.js
  65. 0 31
      frontend/src/components/MainContainer/index.js
  66. 0 19
      frontend/src/components/MainHeader/index.js
  67. 0 21
      frontend/src/components/MainHeaderButtonsWrapper/index.js
  68. 0 186
      frontend/src/components/MarkdownWrapper/index.js
  69. 0 48
      frontend/src/components/MessageInput/RecordingTimer.js
  70. 0 513
      frontend/src/components/MessageInput/index.js
  71. 0 48
      frontend/src/components/MessageInputCustom/RecordingTimer.js
  72. 0 773
      frontend/src/components/MessageInputCustom/index.js
  73. 0 71
      frontend/src/components/MessageOptionsMenu/index.js
  74. 0 66
      frontend/src/components/MessageVariablesPicker/index.js
  75. 0 837
      frontend/src/components/MessagesList/index.js
  76. 0 50
      frontend/src/components/ModalImageCors/index.js
  77. 0 263
      frontend/src/components/ModalUsers/index.js
  78. 0 447
      frontend/src/components/NewTicketModal/index.js
  79. 0 270
      frontend/src/components/NotificationsPopOver/index.js
  80. 0 275
      frontend/src/components/NotificationsPopOver/index_Antigo.js
  81. 0 110
      frontend/src/components/NotificationsVolume/index.js
  82. 0 9
      frontend/src/components/OnlyForSuperUser/index.js
  83. 0 30
      frontend/src/components/OutlinedDiv/index.js
  84. 0 561
      frontend/src/components/PlansManager/index.js
  85. 0 312
      frontend/src/components/PromptModal/index.js
  86. 0 84
      frontend/src/components/QrcodeModal/index.js
  87. 0 505
      frontend/src/components/QueueIntegrationModal/index.js
  88. 0 510
      frontend/src/components/QueueModal/index.js
  89. 0 345
      frontend/src/components/QueueOptions/index.js
  90. 0 90
      frontend/src/components/QueueSelect/index copy.js
  91. 0 112
      frontend/src/components/QueueSelect/index.js
  92. 0 90
      frontend/src/components/QueueSelect/index_erro.js
  93. 0 92
      frontend/src/components/QueueSelectCustom/index.js
  94. 0 68
      frontend/src/components/QueueSelectSingle/index.js
  95. 0 332
      frontend/src/components/QuickMessageDialog/index.js
  96. 0 93
      frontend/src/components/QuickMessagesTable/index.js
  97. 0 382
      frontend/src/components/ScheduleModal/index.js
  98. 0 141
      frontend/src/components/SchedulesForm/index.js
  99. 0 727
      frontend/src/components/Settings/Options.js
  100. 0 70
      frontend/src/components/SubscriptionModal/index.js

+ 0 - 119
frontend/src/App.js

@@ -1,119 +0,0 @@
-import React, { useState, useEffect } from "react";
-
-import "react-toastify/dist/ReactToastify.css";
-import { QueryClient, QueryClientProvider } from "react-query";
-
-import {enUS, ptBR, esES} from "@material-ui/core/locale";
-import { createTheme, ThemeProvider } from "@material-ui/core/styles";
-import { useMediaQuery } from "@material-ui/core";
-import ColorModeContext from "./layout/themeContext";
-import { SocketContext, SocketManager } from './context/Socket/SocketContext';
-
-import Routes from "./routes";
-
-const queryClient = new QueryClient();
-
-const App = () => {
-    const [locale, setLocale] = useState();
-
-    const prefersDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
-    const preferredTheme = window.localStorage.getItem("preferredTheme");
-    const [mode, setMode] = useState(preferredTheme ? preferredTheme : prefersDarkMode ? "dark" : "light");
-
-    const colorMode = React.useMemo(
-        () => ({
-            toggleColorMode: () => {
-                setMode((prevMode) => (prevMode === "light" ? "dark" : "light"));
-            },
-        }),
-        []
-    );
-
-    const theme = createTheme(
-        {
-            scrollbarStyles: {
-                "&::-webkit-scrollbar": {
-                    width: '8px',
-                    height: '8px',
-                },
-                "&::-webkit-scrollbar-thumb": {
-                    boxShadow: 'inset 0 0 6px rgba(0, 0, 0, 0.3)',
-                    backgroundColor: "#682EE3",
-                },
-            },
-            scrollbarStylesSoft: {
-                "&::-webkit-scrollbar": {
-                    width: "8px",
-                },
-                "&::-webkit-scrollbar-thumb": {
-                    backgroundColor: mode === "light" ? "#F3F3F3" : "#333333",
-                },
-            },
-            palette: {
-                type: mode,
-                primary: { main: mode === "light" ? "#682EE3" : "#FFFFFF" },
-                textPrimary: mode === "light" ? "#682EE3" : "#FFFFFF",
-                borderPrimary: mode === "light" ? "#682EE3" : "#FFFFFF",
-                dark: { main: mode === "light" ? "#333333" : "#F3F3F3" },
-                light: { main: mode === "light" ? "#F3F3F3" : "#333333" },
-                tabHeaderBackground: mode === "light" ? "#EEE" : "#666",
-                optionsBackground: mode === "light" ? "#fafafa" : "#333",
-				options: mode === "light" ? "#fafafa" : "#666",
-				fontecor: mode === "light" ? "#128c7e" : "#fff",
-                fancyBackground: mode === "light" ? "#fafafa" : "#333",
-				bordabox: mode === "light" ? "#eee" : "#333",
-				newmessagebox: mode === "light" ? "#eee" : "#333",
-				inputdigita: mode === "light" ? "#fff" : "#666",
-				contactdrawer: mode === "light" ? "#fff" : "#666",
-				announcements: mode === "light" ? "#ededed" : "#333",
-				login: mode === "light" ? "#fff" : "#1C1C1C",
-				announcementspopover: mode === "light" ? "#fff" : "#666",
-				chatlist: mode === "light" ? "#eee" : "#666",
-				boxlist: mode === "light" ? "#ededed" : "#666",
-				boxchatlist: mode === "light" ? "#ededed" : "#333",
-                total: mode === "light" ? "#fff" : "#222",
-                messageIcons: mode === "light" ? "grey" : "#F3F3F3",
-                inputBackground: mode === "light" ? "#FFFFFF" : "#333",
-                barraSuperior: mode === "light" ? "linear-gradient(to right, #682EE3, #682EE3 , #682EE3)" : "#666",
-				boxticket: mode === "light" ? "#EEE" : "#666",
-				campaigntab: mode === "light" ? "#ededed" : "#666",
-				mediainput: mode === "light" ? "#ededed" : "#1c1c1c",
-            },
-            mode,
-        },
-        locale
-    );
-
-    useEffect(() => {
-        const i18nlocale = localStorage.getItem("i18nextLng");
-        const browserLocale = i18nlocale?.substring(0, 2) ?? 'pt';
-
-        if (browserLocale === "pt"){
-            setLocale(ptBR);
-        }else if( browserLocale === "en" ) {
-            setLocale(enUS)
-        }else if( browserLocale === "es" )
-            setLocale(esES)
-
-    }, []);
-
-    useEffect(() => {
-        window.localStorage.setItem("preferredTheme", mode);
-    }, [mode]);
-
-
-
-    return (
-        <ColorModeContext.Provider value={{ colorMode }}>
-            <ThemeProvider theme={theme}>
-                <QueryClientProvider client={queryClient}>
-                  <SocketContext.Provider value={SocketManager}>
-                      <Routes />
-                  </SocketContext.Provider>
-                </QueryClientProvider>
-            </ThemeProvider>
-        </ColorModeContext.Provider>
-    );
-};
-
-export default App;

BIN
frontend/src/assets/chat_notify.mp3


BIN
frontend/src/assets/dialogflow.png


BIN
frontend/src/assets/logo.png


BIN
frontend/src/assets/n8n.png


BIN
frontend/src/assets/planilha.xlsx


BIN
frontend/src/assets/sound.mp3


BIN
frontend/src/assets/sound.ogg


BIN
frontend/src/assets/typebot.jpg


BIN
frontend/src/assets/wa-background-dark.png


BIN
frontend/src/assets/wa-background.png


BIN
frontend/src/assets/webhook.png


+ 0 - 338
frontend/src/components/AnnouncementModal/index.js

@@ -1,338 +0,0 @@
-import React, { useState, useEffect, useRef } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import IconButton from "@material-ui/core/IconButton";
-
-import { i18n } from "../../translate/i18n";
-import { head } from "lodash";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import {
-  FormControl,
-  Grid,
-  InputLabel,
-  MenuItem,
-  Select,
-} from "@material-ui/core";
-import ConfirmationModal from "../ConfirmationModal";
-
-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,
-  },
-  formControl: {
-    margin: theme.spacing(1),
-    minWidth: 120,
-  },
-  colorAdorment: {
-    width: 20,
-    height: 20,
-  },
-}));
-
-const AnnouncementSchema = Yup.object().shape({
-  title: Yup.string().required(i18n.t("announcements.dialog.form.required")),
-  text: Yup.string().required(i18n.t("announcements.dialog.form.required")),
-});
-
-const AnnouncementModal = ({ open, onClose, announcementId, reload }) => {
-  const classes = useStyles();
-
-  const initialState = {
-    title: "",
-    text: "",
-    priority: 3,
-    status: true,
-  };
-
-  const [confirmationOpen, setConfirmationOpen] = useState(false);
-  const [announcement, setAnnouncement] = useState(initialState);
-  const [attachment, setAttachment] = useState(null);
-  const attachmentFile = useRef(null);
-
-  useEffect(() => {
-    try {
-      (async () => {
-        if (!announcementId) return;
-
-        const { data } = await api.get(`/announcements/${announcementId}`);
-        setAnnouncement((prevState) => {
-          return { ...prevState, ...data };
-        });
-      })();
-    } catch (err) {
-      toastError(err);
-    }
-  }, [announcementId, open]);
-
-  const handleClose = () => {
-    setAnnouncement(initialState);
-    setAttachment(null);
-    onClose();
-  };
-
-  const handleAttachmentFile = (e) => {
-    const file = head(e.target.files);
-    if (file) {
-      setAttachment(file);
-    }
-  };
-
-  const handleSaveAnnouncement = async (values) => {
-    const announcementData = { ...values };
-    try {
-      if (announcementId) {
-        await api.put(`/announcements/${announcementId}`, announcementData);
-        if (attachment != null) {
-          const formData = new FormData();
-          formData.append("file", attachment);
-          await api.post(
-            `/announcements/${announcementId}/media-upload`,
-            formData
-          );
-        }
-      } else {
-        const { data } = await api.post("/announcements", announcementData);
-        if (attachment != null) {
-          const formData = new FormData();
-          formData.append("file", attachment);
-          await api.post(`/announcements/${data.id}/media-upload`, formData);
-        }
-      }
-      toast.success(i18n.t("announcements.toasts.success"));
-      if (typeof reload == "function") {
-        reload();
-      }
-    } catch (err) {
-      toastError(err);
-    }
-    handleClose();
-  };
-
-  const deleteMedia = async () => {
-    if (attachment) {
-      setAttachment(null);
-      attachmentFile.current.value = null;
-    }
-
-    if (announcement.mediaPath) {
-      await api.delete(`/announcements/${announcement.id}/media-upload`);
-      setAnnouncement((prev) => ({
-        ...prev,
-        mediaPath: null,
-      }));
-      toast.success(i18n.t("announcements.toasts.deleted"));
-      if (typeof reload == "function") {
-        reload();
-      }
-    }
-  };
-
-  return (
-    <div className={classes.root}>
-      <ConfirmationModal
-        title={i18n.t("announcements.confirmationModal.deleteTitle")}
-        open={confirmationOpen}
-        onClose={() => setConfirmationOpen(false)}
-        onConfirm={deleteMedia}
-      >
-        {i18n.t("announcements.confirmationModal.deleteMessage")}
-      </ConfirmationModal>
-      <Dialog
-        open={open}
-        onClose={handleClose}
-        maxWidth="xs"
-        fullWidth
-        scroll="paper"
-      >
-        <DialogTitle id="form-dialog-title">
-          {announcementId
-            ? `${i18n.t("announcements.dialog.edit")}`
-            : `${i18n.t("announcements.dialog.add")}`}
-        </DialogTitle>
-        <div style={{ display: "none" }}>
-          <input
-            type="file"
-            accept=".png,.jpg,.jpeg"
-            ref={attachmentFile}
-            onChange={(e) => handleAttachmentFile(e)}
-          />
-        </div>
-        <Formik
-          initialValues={announcement}
-          enableReinitialize={true}
-          validationSchema={AnnouncementSchema}
-          onSubmit={(values, actions) => {
-            setTimeout(() => {
-              handleSaveAnnouncement(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ touched, errors, isSubmitting, values }) => (
-            <Form>
-              <DialogContent dividers>
-                <Grid spacing={2} container>
-                  <Grid xs={12} item>
-                    <Field
-                      as={TextField}
-                      label={i18n.t("announcements.dialog.form.title")}
-                      name="title"
-                      error={touched.title && Boolean(errors.title)}
-                      helperText={touched.title && errors.title}
-                      variant="outlined"
-                      margin="dense"
-                      fullWidth
-                    />
-                  </Grid>
-                  <Grid xs={12} item>
-                    <Field
-                      as={TextField}
-                      label={i18n.t("announcements.dialog.form.text")}
-                      name="text"
-                      error={touched.text && Boolean(errors.text)}
-                      helperText={touched.text && errors.text}
-                      variant="outlined"
-                      margin="dense"
-                      multiline={true}
-                      rows={7}
-                      fullWidth
-                    />
-                  </Grid>
-                  <Grid xs={12} item>
-                    <FormControl variant="outlined" margin="dense" fullWidth>
-                      <InputLabel id="status-selection-label">
-                        {i18n.t("announcements.dialog.form.status")}
-                      </InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("announcements.dialog.form.status")}
-                        placeholder={i18n.t("announcements.dialog.form.status")}
-                        labelId="status-selection-label"
-                        id="status"
-                        name="status"
-                        error={touched.status && Boolean(errors.status)}
-                      >
-                        <MenuItem value={true}>Ativo</MenuItem>
-                        <MenuItem value={false}>Inativo</MenuItem>
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  <Grid xs={12} item>
-                    <FormControl variant="outlined" margin="dense" fullWidth>
-                      <InputLabel id="priority-selection-label">
-                        {i18n.t("announcements.dialog.form.priority")}
-                      </InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("announcements.dialog.form.priority")}
-                        placeholder={i18n.t(
-                          "announcements.dialog.form.priority"
-                        )}
-                        labelId="priority-selection-label"
-                        id="priority"
-                        name="priority"
-                        error={touched.priority && Boolean(errors.priority)}
-                      >
-                        <MenuItem value={1}>Alta</MenuItem>
-                        <MenuItem value={2}>Média</MenuItem>
-                        <MenuItem value={3}>Baixa</MenuItem>
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  {(announcement.mediaPath || attachment) && (
-                    <Grid xs={12} item>
-                      <Button startIcon={<AttachFileIcon />}>
-                        {attachment ? attachment.name : announcement.mediaName}
-                      </Button>
-                      <IconButton
-                        onClick={() => setConfirmationOpen(true)}
-                        color="secondary"
-                      >
-                        <DeleteOutlineIcon />
-                      </IconButton>
-                    </Grid>
-                  )}
-                </Grid>
-              </DialogContent>
-              <DialogActions>
-                {!attachment && !announcement.mediaPath && (
-                  <Button
-                    color="primary"
-                    onClick={() => attachmentFile.current.click()}
-                    disabled={isSubmitting}
-                    variant="outlined"
-                  >
-                    {i18n.t("announcements.dialog.buttons.attach")}
-                  </Button>
-                )}
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("announcements.dialog.buttons.cancel")}
-                </Button>
-                <Button
-                  type="submit"
-                  color="primary"
-                  disabled={isSubmitting}
-                  variant="contained"
-                  className={classes.btnWrapper}
-                >
-                  {announcementId
-                    ? `${i18n.t("announcements.dialog.buttons.add")}`
-                    : `${i18n.t("announcements.dialog.buttons.edit")}`}
-                  {isSubmitting && (
-                    <CircularProgress
-                      size={24}
-                      className={classes.buttonProgress}
-                    />
-                  )}
-                </Button>
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div>
-  );
-};
-
-export default AnnouncementModal;

+ 0 - 329
frontend/src/components/AnnouncementsPopover/index.js

@@ -1,329 +0,0 @@
-import React, { useEffect, useReducer, useState, useContext } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import toastError from "../../errors/toastError";
-import Popover from "@material-ui/core/Popover";
-import AnnouncementIcon from "@material-ui/icons/Announcement";
-import Notifications from "@material-ui/icons/Notifications"
-
-import {
-  Avatar,
-  Badge,
-  IconButton,
-  List,
-  ListItem,
-  ListItemAvatar,
-  ListItemText,
-  Dialog,
-  Paper,
-  Typography,
-  DialogTitle,
-  DialogContent,
-  DialogActions,
-  Button,
-  DialogContentText,
-} from "@material-ui/core";
-import api from "../../services/api";
-import { isArray } from "lodash";
-import moment from "moment";
-import { SocketContext } from "../../context/Socket/SocketContext";
-
-const useStyles = makeStyles((theme) => ({
-  mainPaper: {
-    flex: 1,
-    maxHeight: 3000,
-    maxWidth: 5000,
-    padding: theme.spacing(1),
-    overflowY: "scroll",
-    ...theme.scrollbarStyles,
-  },
-}));
-
-function AnnouncementDialog({ announcement, open, handleClose }) {
-  const getMediaPath = (filename) => {
-    return `${process.env.REACT_APP_BACKEND_URL}/public/${filename}`;
-  };
-  return (
-    <Dialog
-      open={open}
-      onClose={() => handleClose()}
-      aria-labelledby="alert-dialog-title"
-      aria-describedby="alert-dialog-description"
-    >
-      <DialogTitle id="alert-dialog-title">{announcement.title}</DialogTitle>
-      <DialogContent>
-        {announcement.mediaPath && (
-          <div
-            style={{
-              border: "1px solid #f1f1f1",
-              margin: "0 auto 20px",
-              textAlign: "center",
-              width: "400px",
-              height: 300,
-              backgroundImage: `url(${getMediaPath(announcement.mediaPath)})`,
-              backgroundRepeat: "no-repeat",
-              backgroundSize: "contain",
-              backgroundPosition: "center",
-            }}
-          ></div>
-        )}
-        <DialogContentText id="alert-dialog-description">
-          {announcement.text}
-        </DialogContentText>
-      </DialogContent>
-      <DialogActions>
-        <Button onClick={() => handleClose()} color="primary" autoFocus>
-          Fechar
-        </Button>
-      </DialogActions>
-    </Dialog>
-  );
-}
-
-const reducer = (state, action) => {
-  if (action.type === "LOAD_ANNOUNCEMENTS") {
-    const announcements = action.payload;
-    const newAnnouncements = [];
-
-    if (isArray(announcements)) {
-      announcements.forEach((announcement) => {
-        const announcementIndex = state.findIndex(
-          (u) => u.id === announcement.id
-        );
-        if (announcementIndex !== -1) {
-          state[announcementIndex] = announcement;
-        } else {
-          newAnnouncements.push(announcement);
-        }
-      });
-    }
-
-    return [...state, ...newAnnouncements];
-  }
-
-  if (action.type === "UPDATE_ANNOUNCEMENTS") {
-    const announcement = action.payload;
-    const announcementIndex = state.findIndex((u) => u.id === announcement.id);
-
-    if (announcementIndex !== -1) {
-      state[announcementIndex] = announcement;
-      return [...state];
-    } else {
-      return [announcement, ...state];
-    }
-  }
-
-  if (action.type === "DELETE_ANNOUNCEMENT") {
-    const announcementId = action.payload;
-
-    const announcementIndex = state.findIndex((u) => u.id === announcementId);
-    if (announcementIndex !== -1) {
-      state.splice(announcementIndex, 1);
-    }
-    return [...state];
-  }
-
-  if (action.type === "RESET") {
-    return [];
-  }
-};
-
-export default function AnnouncementsPopover() {
-  const classes = useStyles();
-
-  const [loading, setLoading] = useState(false);
-  const [anchorEl, setAnchorEl] = useState(null);
-  const [pageNumber, setPageNumber] = useState(1);
-  const [hasMore, setHasMore] = useState(false);
-  const [searchParam] = useState("");
-  const [announcements, dispatch] = useReducer(reducer, []);
-  const [invisible, setInvisible] = useState(false);
-  const [announcement, setAnnouncement] = useState({});
-  const [showAnnouncementDialog, setShowAnnouncementDialog] = useState(false);
-
-  const socketManager = useContext(SocketContext);
-
-  useEffect(() => {
-    dispatch({ type: "RESET" });
-    setPageNumber(1);
-  }, [searchParam]);
-
-  useEffect(() => {
-    setLoading(true);
-    const delayDebounceFn = setTimeout(() => {
-      fetchAnnouncements();
-    }, 500);
-    return () => clearTimeout(delayDebounceFn);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [searchParam, pageNumber]);
-
-  useEffect(() => {
-    const companyId = localStorage.getItem("companyId");
-    const socket = socketManager.getSocket(companyId);
-    
-    if (!socket) {
-      return () => {}; 
-    }
-
-    socket.on(`company-announcement`, (data) => {
-      if (data.action === "update" || data.action === "create") {
-        dispatch({ type: "UPDATE_ANNOUNCEMENTS", payload: data.record });
-        setInvisible(false);
-      }
-      if (data.action === "delete") {
-        dispatch({ type: "DELETE_ANNOUNCEMENT", payload: +data.id });
-      }
-    });
-    return () => {
-      socket.disconnect();
-    };
-  }, [socketManager]);
-
-  const fetchAnnouncements = async () => {
-    try {
-      const { data } = await api.get("/announcements/", {
-        params: { searchParam, pageNumber },
-      });
-      dispatch({ type: "LOAD_ANNOUNCEMENTS", payload: data.records });
-      setHasMore(data.hasMore);
-      setLoading(false);
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  const loadMore = () => {
-    setPageNumber((prevState) => prevState + 1);
-  };
-
-  const handleScroll = (e) => {
-    if (!hasMore || loading) return;
-    const { scrollTop, scrollHeight, clientHeight } = e.currentTarget;
-    if (scrollHeight - (scrollTop + 100) < clientHeight) {
-      loadMore();
-    }
-  };
-
-  const handleClick = (event) => {
-    setAnchorEl(event.currentTarget);
-    setInvisible(true);
-  };
-
-  const handleClose = () => {
-    setAnchorEl(null);
-  };
-
-  const borderPriority = (priority) => {
-    if (priority === 1) {
-      return "4px solid #b81111";
-    }
-    if (priority === 2) {
-      return "4px solid orange";
-    }
-    if (priority === 3) {
-      return "4px solid grey";
-    }
-  };
-
-  const getMediaPath = (filename) => {
-    return `${process.env.REACT_APP_BACKEND_URL}/public/${filename}`;
-  };
-
-  const handleShowAnnouncementDialog = (record) => {
-    setAnnouncement(record);
-    setShowAnnouncementDialog(true);
-    setAnchorEl(null);
-  };
-
-  const open = Boolean(anchorEl);
-  const id = open ? "simple-popover" : undefined;
-
-  return (
-    <div>
-      <AnnouncementDialog
-        announcement={announcement}
-        open={showAnnouncementDialog}
-        handleClose={() => setShowAnnouncementDialog(false)}
-      />
-      <IconButton
-        variant="contained"
-        aria-describedby={id}
-        onClick={handleClick}
-        style={{ color: "white" }}
-      >
-        <Badge
-          color="secondary"
-          variant="dot"
-          invisible={invisible || announcements.length < 1}
-        >
-          <Notifications />
-        </Badge>
-      </IconButton>
-      <Popover
-        id={id}
-        open={open}
-        anchorEl={anchorEl}
-        onClose={handleClose}
-        anchorOrigin={{
-          vertical: "bottom",
-          horizontal: "center",
-        }}
-        transformOrigin={{
-          vertical: "top",
-          horizontal: "center",
-        }}
-      >
-        <Paper
-          variant="outlined"
-          onScroll={handleScroll}
-          className={classes.mainPaper}
-        >
-          <List
-            component="nav"
-            aria-label="main mailbox folders"
-            style={{ minWidth: 300 }}
-          >
-            {isArray(announcements) &&
-              announcements.map((item, key) => (
-                <ListItem
-                  key={key}
-                  style={{
-                    //background: key % 2 === 0 ? "#ededed" : "white",
-                    border: "1px solid #eee",
-                    borderLeft: borderPriority(item.priority),
-                    cursor: "pointer",
-                  }}
-                  onClick={() => handleShowAnnouncementDialog(item)}
-                >
-                  {item.mediaPath && (
-                    <ListItemAvatar>
-                      <Avatar
-                        alt={item.mediaName}
-                        src={getMediaPath(item.mediaPath)}
-                      />
-                    </ListItemAvatar>
-                  )}
-                  <ListItemText
-                    primary={item.title}
-                    secondary={
-                      <>
-                        <Typography component="span" style={{ fontSize: 12 }}>
-                          {moment(item.createdAt).format("DD/MM/YYYY")}
-                        </Typography>
-                        <span style={{ marginTop: 5, display: "block" }}></span>
-                        <Typography component="span" variant="body2">
-                          {item.text}
-                        </Typography>
-                      </>
-                    }
-                  />
-                </ListItem>
-              ))}
-            {isArray(announcements) && announcements.length === 0 && (
-              <ListItemText primary="Nenhum registro" />
-            )}
-          </List>
-        </Paper>
-      </Popover>
-    </div>
-  );
-}

+ 0 - 23
frontend/src/components/BackdropLoading/index.js

@@ -1,23 +0,0 @@
-import React from "react";
-
-import Backdrop from "@material-ui/core/Backdrop";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import { makeStyles } from "@material-ui/core/styles";
-
-const useStyles = makeStyles(theme => ({
-	backdrop: {
-		zIndex: theme.zIndex.drawer + 1,
-		color: "#fff",
-	},
-}));
-
-const BackdropLoading = () => {
-	const classes = useStyles();
-	return (
-		<Backdrop className={classes.backdrop} open={true}>
-			<CircularProgress color="inherit" />
-		</Backdrop>
-	);
-};
-
-export default BackdropLoading;

+ 0 - 35
frontend/src/components/ButtonWithSpinner/index.js

@@ -1,35 +0,0 @@
-import React from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import { CircularProgress, Button } from "@material-ui/core";
-
-const useStyles = makeStyles(theme => ({
-	button: {
-		position: "relative",
-	},
-
-	buttonProgress: {
-		color: green[500],
-		position: "absolute",
-		top: "50%",
-		left: "50%",
-		marginTop: -12,
-		marginLeft: -12,
-	},
-}));
-
-const ButtonWithSpinner = ({ loading, children, ...rest }) => {
-	const classes = useStyles();
-
-	return (
-		<Button className={classes.button} disabled={loading} {...rest}>
-			{children}
-			{loading && (
-				<CircularProgress size={24} className={classes.buttonProgress} />
-			)}
-		</Button>
-	);
-};
-
-export default ButtonWithSpinner;

+ 0 - 634
frontend/src/components/CampaignModal/index.js

@@ -1,634 +0,0 @@
-import React, { useState, useEffect, useRef, useContext } from "react";
-
-import * as Yup from "yup";
-import { Formik, Form, Field } from "formik";
-import { toast } from "react-toastify";
-import { head } from "lodash";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import Button from "@material-ui/core/Button";
-import IconButton from "@material-ui/core/IconButton";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-
-import { i18n } from "../../translate/i18n";
-import moment from "moment";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import {
-  Box,
-  FormControl,
-  Grid,
-  InputLabel,
-  MenuItem,
-  Select,
-  Tab,
-  Tabs,
-} from "@material-ui/core";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import ConfirmationModal from "../ConfirmationModal";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: "flex",
-    flexWrap: "wrap",
-    backgroundColor: "#fff"
-  },
-
-  tabmsg: {
-    backgroundColor: theme.palette.campaigntab,
-  },
-
-  textField: {
-    marginRight: theme.spacing(1),
-    flex: 1,
-  },
-
-  extraAttr: {
-    display: "flex",
-    justifyContent: "center",
-    alignItems: "center",
-  },
-
-  btnWrapper: {
-    position: "relative",
-  },
-
-  buttonProgress: {
-    color: green[500],
-    position: "absolute",
-    top: "50%",
-    left: "50%",
-    marginTop: -12,
-    marginLeft: -12,
-  },
-}));
-
-const CampaignSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, i18n.t("campaigns.dialog.form.nameShort"))
-    .max(50, i18n.t("campaigns.dialog.form.nameLong"))
-    .required(i18n.t("campaigns.dialog.form.nameRequired")),
-});
-
-const CampaignModal = ({
-  open,
-  onClose,
-  campaignId,
-  initialValues,
-  onSave,
-  resetPagination,
-}) => {
-  const classes = useStyles();
-  const isMounted = useRef(true);
-  const { user } = useContext(AuthContext);
-  const { companyId } = user;
-  const [file, setFile] = useState(null);
-
-  const initialState = {
-    name: "",
-    message1: "",
-    message2: "",
-    message3: "",
-    message4: "",
-    message5: "",
-    status: "INATIVA", // INATIVA, PROGRAMADA, EM_ANDAMENTO, CANCELADA, FINALIZADA,
-    scheduledAt: "",
-    whatsappId: "",
-    contactListId: "",
-    tagListId: "Nenhuma",
-    companyId,
-  };
-
-  const [campaign, setCampaign] = useState(initialState);
-  const [whatsapps, setWhatsapps] = useState([]);
-  const [contactLists, setContactLists] = useState([]);
-  const [messageTab, setMessageTab] = useState(0);
-  const [attachment, setAttachment] = useState(null);
-  const [confirmationOpen, setConfirmationOpen] = useState(false);
-  const [campaignEditable, setCampaignEditable] = useState(true);
-  const attachmentFile = useRef(null);
-  const [tagLists, setTagLists] = useState([]);
-
-  useEffect(() => {
-    return () => {
-      isMounted.current = false;
-    };
-  }, []);
-
-  useEffect(() => {
-    (async () => {
-      try {
-        const { data } = await api.get("/files/", {
-          params: { companyId }
-        });
-
-        setFile(data.files);
-      } catch (err) {
-        toastError(err);
-      }
-    })();
-  }, []);
-
-  useEffect(() => {
-    if (isMounted.current) {
-      if (initialValues) {
-        setCampaign((prevState) => {
-          return { ...prevState, ...initialValues };
-        });
-      }
-
-      api
-        .get(`/contact-lists/list`, { params: { companyId } })
-        .then(({ data }) => setContactLists(data));
-
-      api
-        .get(`/whatsapp`, { params: { companyId, session: 0 } })
-        .then(({ data }) => setWhatsapps(data));
-
-      api.get(`/tags`, { params: { companyId } })
-        .then(({ data }) => {
-          const fetchedTags = data.tags;
-          // Perform any necessary data transformation here
-          const formattedTagLists = fetchedTags.map((tag) => ({
-            id: tag.id,
-            name: tag.name,
-          }));
-          setTagLists(formattedTagLists);
-        })
-        .catch((error) => {
-          console.error("Error retrieving tags:", error);
-        });
-        
-      if (!campaignId) return;
-
-      api.get(`/campaigns/${campaignId}`).then(({ data }) => {
-        setCampaign((prev) => {
-          let prevCampaignData = Object.assign({}, prev);
-
-          Object.entries(data).forEach(([key, value]) => {
-            if (key === "scheduledAt" && value !== "" && value !== null) {
-              prevCampaignData[key] = moment(value).format("YYYY-MM-DDTHH:mm");
-            } else {
-              prevCampaignData[key] = value === null ? "" : value;
-            }
-          });
-
-          return {...prevCampaignData, tagListId: data.tagId || "Nenhuma"};
-        });
-      });
-    }
-  }, [campaignId, open, initialValues, companyId]);
-
-  useEffect(() => {
-    const now = moment();
-    const scheduledAt = moment(campaign.scheduledAt);
-    const moreThenAnHour =
-      !Number.isNaN(scheduledAt.diff(now)) && scheduledAt.diff(now, "hour") > 1;
-    const isEditable =
-      campaign.status === "INATIVA" ||
-      (campaign.status === "PROGRAMADA" && moreThenAnHour);
-
-    setCampaignEditable(isEditable);
-  }, [campaign.status, campaign.scheduledAt]);
-
-  const handleClose = () => {
-    onClose();
-    setCampaign(initialState);
-  };
-
-  const handleAttachmentFile = (e) => {
-    const file = head(e.target.files);
-    if (file) {
-      setAttachment(file);
-    }
-  };
-
-  const handleSaveCampaign = async (values) => {
-    try {
-      const dataValues = {};
-      Object.entries(values).forEach(([key, value]) => {
-        if (key === "scheduledAt" && value !== "" && value !== null) {
-          dataValues[key] = moment(value).format("YYYY-MM-DD HH:mm:ss");
-        } else {
-          dataValues[key] = value === "" ? null : value;
-        }
-      });
-
-      if (campaignId) {
-        await api.put(`/campaigns/${campaignId}`, dataValues);
-
-        if (attachment != null) {
-          const formData = new FormData();
-          formData.append("file", attachment);
-          await api.post(`/campaigns/${campaignId}/media-upload`, formData);
-        }
-        handleClose();
-      } else {
-        const { data } = await api.post("/campaigns", dataValues);
-
-        if (attachment != null) {
-          const formData = new FormData();
-          formData.append("file", attachment);
-          await api.post(`/campaigns/${data.id}/media-upload`, formData);
-        }
-        if (onSave) {
-          onSave(data);
-        }
-        handleClose();
-      }
-      toast.success(i18n.t("campaigns.toasts.success"));
-    } catch (err) {
-      console.log(err);
-      toastError(err);
-    }
-  };
-
-  const deleteMedia = async () => {
-    if (attachment) {
-      setAttachment(null);
-      attachmentFile.current.value = null;
-    }
-
-    if (campaign.mediaPath) {
-      await api.delete(`/campaigns/${campaign.id}/media-upload`);
-      setCampaign((prev) => ({ ...prev, mediaPath: null, mediaName: null }));
-      toast.success(i18n.t("campaigns.toasts.deleted"));
-    }
-  };
-
-  const renderMessageField = (identifier) => {
-    return (
-      <Field
-        as={TextField}
-        id={identifier}
-        name={identifier}
-        fullWidth
-        rows={5}
-        label={i18n.t(`campaigns.dialog.form.${identifier}`)}
-        placeholder={i18n.t("campaigns.dialog.form.messagePlaceholder")}
-        multiline={true}
-        variant="outlined"
-        helperText={i18n.t("campaigns.dialog.form.helper")}
-        disabled={!campaignEditable && campaign.status !== "CANCELADA"}
-      />
-    );
-  };
-
-  const cancelCampaign = async () => {
-    try {
-      await api.post(`/campaigns/${campaign.id}/cancel`);
-      toast.success(i18n.t("campaigns.toasts.cancel"));
-      setCampaign((prev) => ({ ...prev, status: "CANCELADA" }));
-      resetPagination();
-    } catch (err) {
-      toast.error(err.message);
-    }
-  };
-
-  const restartCampaign = async () => {
-    try {
-      await api.post(`/campaigns/${campaign.id}/restart`);
-      toast.success(i18n.t("campaigns.toasts.restart"));
-      setCampaign((prev) => ({ ...prev, status: "EM_ANDAMENTO" }));
-      resetPagination();
-    } catch (err) {
-      toast.error(err.message);
-    }
-  };
-
-  return (
-    <div className={classes.root}>
-      <ConfirmationModal
-        title={i18n.t("campaigns.confirmationModal.deleteTitle")}
-        open={confirmationOpen}
-        onClose={() => setConfirmationOpen(false)}
-        onConfirm={deleteMedia}
-      >
-        {i18n.t("campaigns.confirmationModal.deleteMessage")}
-      </ConfirmationModal>
-      <Dialog
-        open={open}
-        onClose={handleClose}
-        fullWidth
-        maxWidth="md"
-        scroll="paper"
-      >
-        <DialogTitle id="form-dialog-title">
-          {campaignEditable ? (
-            <>
-              {campaignId
-                ? `${i18n.t("campaigns.dialog.update")}`
-                : `${i18n.t("campaigns.dialog.new")}`}
-            </>
-          ) : (
-            <>{`${i18n.t("campaigns.dialog.readonly")}`}</>
-          )}
-        </DialogTitle>
-        <div style={{ display: "none" }}>
-          <input
-            type="file"
-            ref={attachmentFile}
-            onChange={(e) => handleAttachmentFile(e)}
-          />
-        </div>
-        <Formik
-          initialValues={campaign}
-          enableReinitialize={true}
-          validationSchema={CampaignSchema}
-          onSubmit={(values, actions) => {
-            setTimeout(() => {
-              handleSaveCampaign(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ values, errors, touched, isSubmitting }) => (
-            <Form>
-              <DialogContent dividers>
-                <Grid spacing={2} container>
-                  <Grid xs={12} md={9} item>
-                    <Field
-                      as={TextField}
-                      label={i18n.t("campaigns.dialog.form.name")}
-                      name="name"
-                      error={touched.name && Boolean(errors.name)}
-                      helperText={touched.name && errors.name}
-                      variant="outlined"
-                      margin="dense"
-                      fullWidth
-                      className={classes.textField}
-                      disabled={!campaignEditable}
-                    />
-                  </Grid>
-                  <Grid xs={12} md={4} item>
-                    <FormControl
-                      variant="outlined"
-                      margin="dense"
-                      fullWidth
-                      className={classes.formControl}
-                    >
-                      <InputLabel id="contactList-selection-label">
-                        {i18n.t("campaigns.dialog.form.contactList")}
-                      </InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("campaigns.dialog.form.contactList")}
-                        placeholder={i18n.t(
-                          "campaigns.dialog.form.contactList"
-                        )}
-                        labelId="contactList-selection-label"
-                        id="contactListId"
-                        name="contactListId"
-                        error={
-                          touched.contactListId && Boolean(errors.contactListId)
-                        }
-                        disabled={!campaignEditable}
-                      >
-                        <MenuItem value="">Nenhuma</MenuItem>
-                        {contactLists &&
-                          contactLists.map((contactList) => (
-                            <MenuItem
-                              key={contactList.id}
-                              value={contactList.id}
-                            >
-                              {contactList.name}
-                            </MenuItem>
-                          ))}
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  <Grid xs={12} md={4} item>
-                    <FormControl
-                      variant="outlined"
-                      margin="dense"
-                      fullWidth
-                      className={classes.formControl}
-                    >
-                      <InputLabel id="tagList-selection-label">
-                        {i18n.t("campaigns.dialog.form.tagList")}
-                      </InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("campaigns.dialog.form.tagList")}
-                        placeholder={i18n.t("campaigns.dialog.form.tagList")}
-                        labelId="tagList-selection-label"
-                        id="tagListId"
-                        name="tagListId"
-                        error={touched.tagListId && Boolean(errors.tagListId)}
-                        disabled={!campaignEditable}
-                      >
-                        <MenuItem value="">Nenhuma</MenuItem>
-                        {Array.isArray(tagLists) &&
-                          tagLists.map((tagList) => (
-                            <MenuItem key={tagList.id} value={tagList.id}>
-                              {tagList.name}
-                            </MenuItem>
-                          ))}
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  <Grid xs={12} md={4} item>
-                    <FormControl
-                      variant="outlined"
-                      margin="dense"
-                      fullWidth
-                      className={classes.formControl}
-                    >
-                      <InputLabel id="whatsapp-selection-label">
-                        {i18n.t("campaigns.dialog.form.whatsapp")}
-                      </InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("campaigns.dialog.form.whatsapp")}
-                        placeholder={i18n.t("campaigns.dialog.form.whatsapp")}
-                        labelId="whatsapp-selection-label"
-                        id="whatsappId"
-                        name="whatsappId"
-                        error={touched.whatsappId && Boolean(errors.whatsappId)}
-                        disabled={!campaignEditable}
-                      >
-                        <MenuItem value="">Nenhuma</MenuItem>
-                        {whatsapps &&
-                          whatsapps.map((whatsapp) => (
-                            <MenuItem key={whatsapp.id} value={whatsapp.id}>
-                              {whatsapp.name}
-                            </MenuItem>
-                          ))}
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  <Grid xs={12} md={4} item>
-                    <Field
-                      as={TextField}
-                      label={i18n.t("campaigns.dialog.form.scheduledAt")}
-                      name="scheduledAt"
-                      error={touched.scheduledAt && Boolean(errors.scheduledAt)}
-                      helperText={touched.scheduledAt && errors.scheduledAt}
-                      variant="outlined"
-                      margin="dense"
-                      type="datetime-local"
-                      InputLabelProps={{
-                        shrink: true,
-                      }}
-                      fullWidth
-                      className={classes.textField}
-                      disabled={!campaignEditable}
-                    />
-                  </Grid>
-                  <Grid xs={12} md={4} item>
-                  <FormControl
-                      variant="outlined"
-                      margin="dense"
-                      className={classes.FormControl}
-                      fullWidth
-                    >
-                      <InputLabel id="fileListId-selection-label">{i18n.t("campaigns.dialog.form.fileList")}</InputLabel>
-                      <Field
-                        as={Select}
-                        label={i18n.t("campaigns.dialog.form.fileList")}
-                        name="fileListId"
-                        id="fileListId"
-                        placeholder={i18n.t("campaigns.dialog.form.fileList")}
-                        labelId="fileListId-selection-label"
-                        value={values.fileListId || ""}
-                      >
-                        <MenuItem value={""} >{"Nenhum"}</MenuItem>
-                        {file.map(f => (
-                          <MenuItem key={f.id} value={f.id}>
-                            {f.name}
-                          </MenuItem>
-                        ))}
-                      </Field>
-                    </FormControl>
-                  </Grid>
-                  <Grid xs={12} item>
-                    <Tabs
-                      value={messageTab}
-                      indicatorColor="primary"
-                      textColor="primary"
-                      className={classes.tabmsg}
-                      onChange={(e, v) => setMessageTab(v)}
-                      variant="fullWidth"
-                      centered
-                      style={{
-                        borderRadius: 2,
-                      }}
-                    >
-                      <Tab label="Msg. 1" index={0} />
-                      <Tab label="Msg. 2" index={1} />
-                      <Tab label="Msg. 3" index={2} />
-                      <Tab label="Msg. 4" index={3} />
-                      <Tab label="Msg. 5" index={4} />
-                    </Tabs>
-                    <Box style={{ paddingTop: 20, border: "none" }}>
-                      {messageTab === 0 && (
-                        <>{renderMessageField("message1")}</>
-                      )}
-                      {messageTab === 1 && (
-                        <>{renderMessageField("message2")}</>
-                      )}
-                      {messageTab === 2 && (
-                        <>{renderMessageField("message3")}</>
-                      )}
-                      {messageTab === 3 && (
-                        <>{renderMessageField("message4")}</>
-                      )}
-                      {messageTab === 4 && (
-                        <>{renderMessageField("message5")}</>
-                      )}
-                    </Box>
-                  </Grid>
-                  {(campaign.mediaPath || attachment) && (
-                    <Grid xs={12} item>
-                      <Button startIcon={<AttachFileIcon />}>
-                        {attachment != null
-                          ? attachment.name
-                          : campaign.mediaName}
-                      </Button>
-                      {campaignEditable && (
-                        <IconButton
-                          onClick={() => setConfirmationOpen(true)}
-                          color="secondary"
-                        >
-                          <DeleteOutlineIcon />
-                        </IconButton>
-                      )}
-                    </Grid>
-                  )}
-                </Grid>
-              </DialogContent>
-              <DialogActions>
-                {campaign.status === "CANCELADA" && (
-                  <Button
-                    color="primary"
-                    onClick={() => restartCampaign()}
-                    variant="outlined"
-                  >
-                    {i18n.t("campaigns.dialog.buttons.restart")}
-                  </Button>
-                )}
-                {campaign.status === "EM_ANDAMENTO" && (
-                  <Button
-                    color="primary"
-                    onClick={() => cancelCampaign()}
-                    variant="outlined"
-                  >
-                    {i18n.t("campaigns.dialog.buttons.cancel")}
-                  </Button>
-                )}
-                {!attachment && !campaign.mediaPath && campaignEditable && (
-                  <Button
-                    color="primary"
-                    onClick={() => attachmentFile.current.click()}
-                    disabled={isSubmitting}
-                    variant="outlined"
-                  >
-                    {i18n.t("campaigns.dialog.buttons.attach")}
-                  </Button>
-                )}
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("campaigns.dialog.buttons.close")}
-                </Button>
-                {(campaignEditable || campaign.status === "CANCELADA") && (
-                  <Button
-                    type="submit"
-                    color="primary"
-                    disabled={isSubmitting}
-                    variant="contained"
-                    className={classes.btnWrapper}
-                  >
-                    {campaignId
-                      ? `${i18n.t("campaigns.dialog.buttons.edit")}`
-                      : `${i18n.t("campaigns.dialog.buttons.add")}`}
-                    {isSubmitting && (
-                      <CircularProgress
-                        size={24}
-                        className={classes.buttonProgress}
-                      />
-                    )}
-                  </Button>
-                )}
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div>
-  );
-};
-
-export default CampaignModal;

+ 0 - 39
frontend/src/components/Can/index.js

@@ -1,39 +0,0 @@
-import rules from "../../rules";
-
-const check = (role, action, data) => {
-	const permissions = rules[role];
-	if (!permissions) {
-		// role is not present in the rules
-		return false;
-	}
-
-	const staticPermissions = permissions.static;
-
-	if (staticPermissions && staticPermissions.includes(action)) {
-		// static rule not provided for action
-		return true;
-	}
-
-	const dynamicPermissions = permissions.dynamic;
-
-	if (dynamicPermissions) {
-		const permissionCondition = dynamicPermissions[action];
-		if (!permissionCondition) {
-			// dynamic rule not provided for action
-			return false;
-		}
-
-		return permissionCondition(data);
-	}
-	return false;
-};
-
-const Can = ({ role, perform, data, yes, no }) =>
-	check(role, perform, data) ? yes() : no();
-
-Can.defaultProps = {
-	yes: () => null,
-	no: () => null,
-};
-
-export { Can };

+ 0 - 175
frontend/src/components/CheckoutPage/CheckoutPage.js

@@ -1,175 +0,0 @@
-import React, { useContext, useState } from "react";
-import {
-  Stepper,
-  Step,
-  StepLabel,
-  Button,
-  Typography,
-  CircularProgress,
-} from "@material-ui/core";
-import { Formik, Form } from "formik";
-
-import AddressForm from "./Forms/AddressForm";
-import PaymentForm from "./Forms/PaymentForm";
-import ReviewOrder from "./ReviewOrder";
-import CheckoutSuccess from "./CheckoutSuccess";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { toast } from "react-toastify";
-import { AuthContext } from "../../context/Auth/AuthContext";
-
-
-import validationSchema from "./FormModel/validationSchema";
-import checkoutFormModel from "./FormModel/checkoutFormModel";
-import formInitialValues from "./FormModel/formInitialValues";
-
-import useStyles from "./styles";
-import Invoices from "../../pages/Financeiro";
-import { i18n } from "../../translate/i18n";
-
-
-export default function CheckoutPage(props) {
-  const steps = [i18n.t("checkoutPage.steps.data"), i18n.t("checkoutPage.steps.customize"), i18n.t("checkoutPage.steps.review")];
-  const { formId, formField } = checkoutFormModel;
-  
-  
-  
-  const classes = useStyles();
-  const [activeStep, setActiveStep] = useState(1);
-  const [datePayment, setDatePayment] = useState(null);
-  const [invoiceId, setinvoiceId] = useState(props.Invoice.id);
-  const currentValidationSchema = validationSchema[activeStep];
-  const isLastStep = activeStep === steps.length - 1;
-  const { user } = useContext(AuthContext);
-
-function _renderStepContent(step, setFieldValue, setActiveStep, values ) {
-
-  switch (step) {
-    case 0:
-      return <AddressForm formField={formField} values={values} setFieldValue={setFieldValue}  />;
-    case 1:
-      return <PaymentForm 
-      formField={formField} 
-      setFieldValue={setFieldValue} 
-      setActiveStep={setActiveStep} 
-      activeStep={step} 
-      invoiceId={invoiceId}
-      values={values}
-      />;
-    case 2:
-      return <ReviewOrder />;
-    default:
-      return <div>Not Found</div>;
-  }
-}
-
-
-  async function _submitForm(values, actions) {
-    try {
-      const plan = JSON.parse(values.plan);
-      const newValues = {
-        firstName: values.firstName,
-        lastName: values.lastName,
-        address2: values.address2,
-        city: values.city,
-        state: values.state,
-        zipcode: values.zipcode,
-        country: values.country,
-        useAddressForPaymentDetails: values.useAddressForPaymentDetails,
-        nameOnCard: values.nameOnCard,
-        cardNumber: values.cardNumber,
-        cvv: values.cvv,
-        plan: values.plan,
-        price: plan.price,
-        users: plan.users,
-        connections: plan.connections,
-        invoiceId: invoiceId
-      }
-
-      const { data } = await api.post("/subscription", newValues);
-      setDatePayment(data)
-      actions.setSubmitting(false);
-      setActiveStep(activeStep + 1);
-      toast.success(i18n.t("checkoutPage.success"));
-    } catch (err) {
-      toastError(err);
-    }
-  }
-
-  function _handleSubmit(values, actions) {
-    if (isLastStep) {
-      _submitForm(values, actions);
-    } else {
-      setActiveStep(activeStep + 1);
-      actions.setTouched({});
-      actions.setSubmitting(false);
-    }
-  }
-
-  function _handleBack() {
-    setActiveStep(activeStep - 1);
-  }
-
-  return (
-    <React.Fragment>
-      <Typography component="h1" variant="h4" align="center">
-        {i18n.t("checkoutPage.closeToEnd")}
-      </Typography>
-      <Stepper activeStep={activeStep} className={classes.stepper}>
-        {steps.map((label) => (
-          <Step key={label}>
-            <StepLabel>{label}</StepLabel>
-          </Step>
-        ))}
-      </Stepper>
-      <React.Fragment>
-        {activeStep === steps.length ? (
-          <CheckoutSuccess pix={datePayment} />
-        ) : (
-          <Formik
-            initialValues={{
-              ...user, 
-              ...formInitialValues
-            }}
-            validationSchema={currentValidationSchema}
-            onSubmit={_handleSubmit}
-          >
-            {({ isSubmitting, setFieldValue, values }) => (
-              <Form id={formId}>
-                {_renderStepContent(activeStep, setFieldValue, setActiveStep, values)}
-
-                <div className={classes.buttons}>
-                  {activeStep !== 1 && (
-                    <Button onClick={_handleBack} className={classes.button}>
-                      {i18n.t("checkoutPage.BACK")}
-                    </Button>
-                  )}
-                  <div className={classes.wrapper}>
-                    {activeStep !== 1 && (
-                      <Button
-                        disabled={isSubmitting}
-                        type="submit"
-                        variant="contained"
-                        color="primary"
-                        className={classes.button}
-                      >
-                        {isLastStep ? i18n.t("checkoutPage.PAY") : i18n.t("checkoutPage.NEXT")}
-                      </Button>
-                    )}
-                    {isSubmitting && (
-                      <CircularProgress
-                        size={24}
-                        className={classes.buttonProgress}
-                      />
-                    )}
-                  </div>
-                </div>
-              </Form>
-            )}
-          </Formik>
-        )}
-      </React.Fragment>
-    </React.Fragment>
-  );
-}

+ 0 - 76
frontend/src/components/CheckoutPage/CheckoutSuccess/CheckoutSuccess.js

@@ -1,76 +0,0 @@
-import React, { useState, useEffect, useContext } from 'react';
-import { useHistory } from "react-router-dom";
-import QRCode from 'react-qr-code';
-import { SuccessContent, Total } from './style';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
-import { FaCopy, FaCheckCircle } from 'react-icons/fa';
-import { SocketContext } from "../../../context/Socket/SocketContext";
-import { useDate } from "../../../hooks/useDate";
-import { toast } from "react-toastify";
-
-function CheckoutSuccess(props) {
-
-  const { pix } = props;
-  const [pixString,] = useState(pix.qrcode.qrcode);
-  const [copied, setCopied] = useState(false);
-  const history = useHistory();
-
-  const { dateToClient } = useDate();
-
-  const socketManager = useContext(SocketContext);
-
-  useEffect(() => {
-    const companyId = localStorage.getItem("companyId");
-    const socket = socketManager.getSocket(companyId);
-    
-    socket.on(`company-${companyId}-payment`, (data) => {
-
-      if (data.action === "CONCLUIDA") {
-        toast.success(`Sua licença foi renovada até ${dateToClient(data.company.dueDate)}!`);
-        setTimeout(() => {
-          history.push("/");
-        }, 4000);
-      }
-    });
-  }, [history, socketManager]);
-
-  const handleCopyQR = () => {
-    setTimeout(() => {
-      setCopied(false);
-    }, 1 * 1000);
-    setCopied(true);
-  };
-
-  return (
-    <React.Fragment>
-      <Total>
-        <span>TOTAL</span>
-        <strong>R${pix.valor.original.toLocaleString('pt-br', { minimumFractionDigits: 2 })}</strong>
-      </Total>
-      <SuccessContent>
-        <QRCode value={pixString} />
-        <CopyToClipboard text={pixString} onCopy={handleCopyQR}>
-          <button className="copy-button" type="button">
-            {copied ? (
-              <>
-                <span>Copiado</span>
-                <FaCheckCircle size={18} />
-              </>
-            ) : (
-              <>
-                <span>Copiar código QR</span>
-                <FaCopy size={18} />
-              </>
-            )}
-          </button>
-        </CopyToClipboard>
-        <span>
-          Para finalizar, basta realizar o pagamento escaneando ou colando o
-          código Pix acima :)
-        </span>
-      </SuccessContent>
-    </React.Fragment>
-  );
-}
-
-export default CheckoutSuccess;

+ 0 - 2
frontend/src/components/CheckoutPage/CheckoutSuccess/index.js

@@ -1,2 +0,0 @@
-import CheckoutSuccess from './CheckoutSuccess';
-export default CheckoutSuccess;

+ 0 - 117
frontend/src/components/CheckoutPage/CheckoutSuccess/style.js

@@ -1,117 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
-  footer {
-    margin-top: 30px;
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    width: 100%;
-
-    @media (max-width: 768px) {
-      flex-direction: column;
-      .checkout-buttons {
-        display: flex;
-        flex-direction: column-reverse;
-        width: 100%;
-
-        button {
-          width: 100%;
-          margin-top: 16px;
-          margin-left: 0;
-        }
-      }
-    }
-
-    button {
-      margin-left: 16px;
-    }
-  }
-`;
-export const Total = styled.div`
-  display: flex;
-  align-items: baseline;
-
-  span {
-    color: #333;
-    font-weight: bold;
-  }
-
-  strong {
-    color: #333;
-    font-size: 28px;
-    margin-left: 5px;
-  }
-
-  @media (max-width: 768px) {
-    min-width: 100%;
-    justify-content: space-between;
-  }
-`;
-
-export const SuccessContent = styled.div`
-  display: flex;
-  flex-direction: column;
-  justify-content: center;
-  align-items: center;
-
-  > h2 {
-    text-align: center;
-  }
-
-  > svg {
-    margin-top: 16px;
-  }
-
-  > span {
-    margin-top: 24px;
-    text-align: center;
-  }
-
-  > p,
-  strong {
-    margin-top: 8px;
-    font-size: 9px;
-    color: #999;
-  }
-
-  .copy-button {
-    font-size: 14px;
-    cursor: pointer;
-    text-align: center;
-    user-select: none;
-    min-height: 56px;
-    display: inline-flex;
-    -webkit-box-pack: center;
-    justify-content: center;
-    -webkit-box-align: center;
-    align-items: center;
-    background-color: #f9f9f9;
-    color: #000;
-    -webkit-appearance: none !important;
-    outline: none;
-    margin-top: 16px;
-    width: 256px;
-    font-weight: 600;
-    text-transform: uppercase;
-    border: none;
-
-    > span {
-      margin-right: 8px;
-    }
-  }
-`;
-
-export const CheckoutWrapper = styled.div`
-  width: 100%;
-  margin: 0 auto 0;
-  max-width: 1110px;
-  display: flex;
-  flex-direction: column;
-  -webkit-box-align: center;
-  align-items: center;
-  padding: 50px 95px;
-  background: #fff;
-  @media (max-width: 768px) {
-    padding: 16px 24px;
-`;

+ 0 - 75
frontend/src/components/CheckoutPage/FormModel/checkoutFormModel.js

@@ -1,75 +0,0 @@
-import { i18n } from "../../../translate/i18n";
-
-export default {
-  formId: 'checkoutForm',
-  formField: {
-    firstName: {
-      name: 'firstName',
-      label: i18n.t('checkoutPage.form.firstName.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.firstName.required')
-    },
-    lastName: {
-      name: 'lastName',
-      label: i18n.t('checkoutPage.form.lastName.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.lastName.required')
-    },
-    address1: {
-      name: 'address2',
-      label: i18n.t('checkoutPage.form.address1.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.address1.required')
-    },
-
-    city: {
-      name: 'city',
-      label: i18n.t('checkoutPage.form.city.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.city.required')
-    },
-    state: {
-      name: 'state',
-      label: i18n.t('checkoutPage.form.state.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.state.required')
-    },
-    zipcode: {
-      name: 'zipcode',
-      label: i18n.t('checkoutPage.form.zipcode.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.zipcode.required'),
-      invalidErrorMsg: i18n.t('checkoutPage.form.zipcode.invalid')
-    },
-    country: {
-      name: 'country',
-      label: i18n.t('checkoutPage.form.country.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.country.required')
-    },
-    useAddressForPaymentDetails: {
-      name: 'useAddressForPaymentDetails',
-      label: i18n.t('checkoutPage.form.useAddressForPaymentDetails.label')
-    },
-    invoiceId: {
-      name: 'invoiceId',
-      label: i18n.t('checkoutPage.form.invoiceId.label'),
-    },
-    nameOnCard: {
-      name: 'nameOnCard',
-      label: i18n.t('checkoutPage.form.nameOnCard.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.nameOnCard.required')
-    },
-    cardNumber: {
-      name: 'cardNumber',
-      label: i18n.t('checkoutPage.form.cardNumber.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.cardNumber.required'),
-      invalidErrorMsg: i18n.t('checkoutPage.form.cardNumber.invalid')
-    },
-    expiryDate: {
-      name: 'expiryDate',
-      label: i18n.t('checkoutPage.form.expiryDate.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.expiryDate.required'),
-      invalidErrorMsg: i18n.t('checkoutPage.form.expiryDate.invalid')
-    },
-    cvv: {
-      name: 'cvv',
-      label: i18n.t('checkoutPage.form.cvv.label'),
-      requiredErrorMsg: i18n.t('checkoutPage.form.cvv.required'),
-      invalidErrorMsg: i18n.t('checkoutPage.form.cvv.invalid')
-    }
-  }
-};

+ 0 - 32
frontend/src/components/CheckoutPage/FormModel/formInitialValues.js

@@ -1,32 +0,0 @@
-import checkoutFormModel from './checkoutFormModel';
-const {
-  formField: {
-    firstName,
-    lastName,
-    address1,
-    city,
-    state,
-    zipcode,
-    country,
-    useAddressForPaymentDetails,
-    nameOnCard,
-    cardNumber,
-    invoiceId,
-    cvv
-  }
-} = checkoutFormModel;
-
-export default {
-  [firstName.name]: '',
-  [lastName.name]: '',
-  [address1.name]: '',
-  [city.name]: '',
-  [state.name]: '',
-  [zipcode.name]: '',
-  [country.name]: '',
-  [useAddressForPaymentDetails.name]: false,
-  [nameOnCard.name]: '',
-  [cardNumber.name]: '',
-  [invoiceId.name]: '',
-  [cvv.name]: ''
-};

+ 0 - 29
frontend/src/components/CheckoutPage/FormModel/validationSchema.js

@@ -1,29 +0,0 @@
-import * as Yup from 'yup';
-import checkoutFormModel from './checkoutFormModel';
-const {
-  formField: {
-    firstName,
-    address1,
-    city,
-    zipcode,
-    country,
-  }
-} = checkoutFormModel;
-
-
-export default [
-  Yup.object().shape({
-    [firstName.name]: Yup.string().required(`${firstName.requiredErrorMsg}`),
-    [address1.name]: Yup.string().required(`${address1.requiredErrorMsg}`),
-    [city.name]: Yup.string()
-      .nullable()
-      .required(`${city.requiredErrorMsg}`),
-    [zipcode.name]: Yup.string()
-      .required(`${zipcode.requiredErrorMsg}`),
-
-    [country.name]: Yup.string()
-      .nullable()
-      .required(`${country.requiredErrorMsg}`)
-  }),
-
-];

+ 0 - 134
frontend/src/components/CheckoutPage/Forms/AddressForm.js

@@ -1,134 +0,0 @@
-import React, { useContext, useEffect, useState } from "react";
-import { Grid, Typography } from "@material-ui/core";
-import { InputField, SelectField } from "../../FormFields";
-import { AuthContext } from "../../../context/Auth/AuthContext";
-
-const countries = [
-  {
-    value: "BR",
-    label: "Brasil",
-  },
-  {
-    value: "usa",
-    label: "United States",
-  },
-];
-
-export default function AddressForm(props) {
-
-  const { user } = useContext(AuthContext);
-  const [billingName, setBillingName] = useState(user.company.billingName);
-  const [addressZipCode, setAddressZipCode] = useState(user.company.addressZipCode);
-  const [addressStreet, setAddressStreet] = useState(user.company.addressStreet);
-  const [addressState, setAddressState] = useState(user.company.addressState);
-  const [addressCity, setAddressCity] = useState(user.company.addressCity);
-  const [addressDistrict, setAddressDistrict] = useState(user.company.addressDistrict);
-
-  const {
-    formField: {
-      firstName,
-      address1,
-      city,
-      state,
-      zipcode,
-      country,
-    },
-    setFieldValue
-  } = props;
-  useEffect(() => {
-    setFieldValue("firstName", billingName)
-    setFieldValue("zipcode", addressZipCode)
-    setFieldValue("address2", addressStreet)
-    setFieldValue("state", addressState)
-    setFieldValue("city", addressCity)
-    setFieldValue("country", addressDistrict)
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [])
-
-  return (
-    <React.Fragment>
-      <Typography variant="h6" gutterBottom>
-        Vamos precisar de algumas informações
-      </Typography>
-      <Grid container spacing={3}>
-
-        <Grid item xs={6} sm={6}>
-          <InputField name={firstName.name} label={firstName.label} fullWidth
-            value={billingName}
-            onChange={(e) => {
-              setBillingName(e.target.value)
-              setFieldValue("firstName", e.target.value)
-            }}
-          />
-        </Grid>
-        <Grid item xs={6} sm={6}>
-          <SelectField
-            name={country.name}
-            label={country.label}
-            data={countries}
-            fullWidth
-            value={addressDistrict}
-            onChange={(e) => {
-              setAddressDistrict(e.target.value)
-              setFieldValue("country", e.target.value)
-            }
-            }
-          />
-        </Grid>
-
-        <Grid item xs={4}>
-          <InputField
-            name={zipcode.name}
-            label={zipcode.label}
-            fullWidth
-            value={addressZipCode}
-            onChange={(e) => {
-              setAddressZipCode(e.target.value)
-              setFieldValue("zipcode", e.target.value)
-            }}
-          />
-        </Grid>
-        <Grid item xs={8}>
-          <InputField
-            name={address1.name}
-            label={address1.label}
-            fullWidth
-            value={addressStreet}
-            onChange={(e) => {
-              setAddressStreet(e.target.value)
-              setFieldValue("address2", e.target.value)
-
-            }}
-          />
-        </Grid>
-
-        <Grid item xs={4}>
-          <InputField
-            name={state.name}
-            label={state.label}
-            fullWidth
-            value={addressState}
-            onChange={(e) => {
-              setAddressState(e.target.value)
-              setFieldValue("state", e.target.value)
-
-            }}
-          />
-        </Grid>
-        <Grid item xs={8}>
-          <InputField
-            name={city.name}
-            label={city.label}
-            fullWidth
-            value={addressCity}
-            onChange={(e) => {
-              setAddressCity(e.target.value)
-              setFieldValue("city", e.target.value)
-            }}
-          />
-        </Grid>
-
-      </Grid>
-    </React.Fragment>
-  );
-}

+ 0 - 238
frontend/src/components/CheckoutPage/Forms/PaymentForm.js

@@ -1,238 +0,0 @@
-import React, { useState, useEffect, useReducer } from 'react';
-import Button from '@material-ui/core/Button';
-import Card from '@material-ui/core/Card';
-import CardActions from '@material-ui/core/CardActions';
-import CardContent from '@material-ui/core/CardContent';
-import CardHeader from '@material-ui/core/CardHeader';
-import Grid from '@material-ui/core/Grid';
-import StarIcon from '@material-ui/icons/StarBorder';
-import Typography from '@material-ui/core/Typography';
-import { makeStyles } from '@material-ui/core/styles';
-
-import IconButton from '@material-ui/core/IconButton';
-import MinimizeIcon from '@material-ui/icons/Minimize';
-import AddIcon from '@material-ui/icons/Add';
-
-import usePlans from "../../../hooks/usePlans";
-import useCompanies from "../../../hooks/useCompanies";
-import { i18n } from '../../../translate/i18n';
-
-const useStyles = makeStyles((theme) => ({
-  '@global': {
-    ul: {
-      margin: 0,
-      padding: 0,
-      listStyle: 'none',
-    },
-  },
-  margin: {
-    margin: theme.spacing(1),
-  },
-
-
-  cardHeader: {
-    backgroundColor:
-      theme.palette.type === 'light' ? theme.palette.grey[200] : theme.palette.grey[700],
-  },
-  cardPricing: {
-    display: 'flex',
-    justifyContent: 'center',
-    alignItems: 'baseline',
-    marginBottom: theme.spacing(2),
-  },
-  footer: {
-    borderTop: `1px solid ${theme.palette.divider}`,
-    marginTop: theme.spacing(8),
-    paddingTop: theme.spacing(3),
-    paddingBottom: theme.spacing(3),
-    [theme.breakpoints.up('sm')]: {
-      paddingTop: theme.spacing(6),
-      paddingBottom: theme.spacing(6),
-    },
-  },
-
-  customCard: {
-    display: "flex",
-    marginTop: "16px",
-    alignItems: "center",
-    flexDirection: "column",
-  },
-  custom: {
-    display: "flex",
-    alignItems: "center",
-    justifyContent: "space-between",
-  }
-}));
-
-
-export default function Pricing(props) {
-  const {
-    setFieldValue,
-    setActiveStep,
-    activeStep,
-  } = props;
-
-  const handleChangeAdd = (event, newValue) => {
-    if (newValue < 3) return
-
-    const newPrice = 11.00;
-
-    setUsersPlans(newValue);
-    setCustomValuePlans(customValuePlans + newPrice);
-  }
-
-  const handleChangeMin = (event, newValue) => {
-    if (newValue < 3) return
-
-    const newPrice = 11;
-
-    setUsersPlans(newValue);
-    setCustomValuePlans(customValuePlans - newPrice);
-  }
-
-  const handleChangeConnectionsAdd = (event, newValue) => {
-    if (newValue < 3) return
-    const newPrice = 20.00;
-    setConnectionsPlans(newValue);
-    setCustomValuePlans(customValuePlans + newPrice);
-  }
-
-  const handleChangeConnectionsMin = (event, newValue) => {
-    if (newValue < 3) return
-    const newPrice = 20;
-    setConnectionsPlans(newValue);
-    setCustomValuePlans(customValuePlans - newPrice);
-  }
-
-  const { list, finder } = usePlans();
-  const { find } = useCompanies();
-
-  const classes = useStyles();
-  const [usersPlans, setUsersPlans] = React.useState(3);
-  const [companiesPlans, setCompaniesPlans] = useState(0);
-  const [connectionsPlans, setConnectionsPlans] = React.useState(3);
-  const [storagePlans, setStoragePlans] = React.useState([]);
-  const [customValuePlans, setCustomValuePlans] = React.useState(49.00);
-  const [loading, setLoading] = React.useState(false);
-  const companyId = localStorage.getItem("companyId");
-
-  useEffect(() => {
-    async function fetchData() {
-      await loadCompanies();
-    }
-    fetchData();
-  }, [])
-
-  const loadCompanies = async () => {
-    setLoading(true);
-    try {
-      const companiesList = await find(companyId);
-      setCompaniesPlans(companiesList.planId);
-      await loadPlans(companiesList.planId);
-    } catch (e) {
-      console.log(e);
-      // toast.error("Não foi possível carregar a lista de registros");
-    }
-    setLoading(false);
-  };
-  const loadPlans = async (companiesPlans) => {
-    setLoading(true);
-    try {
-      const plansCompanies = await finder(companiesPlans);
-      const plans = []
-
-      //plansCompanies.forEach((plan) => {
-      plans.push({
-        title: plansCompanies.name,
-        planId: plansCompanies.id,
-        price: plansCompanies.value,
-        description: [
-          `${plansCompanies.users} ${i18n.t("checkoutPage.pricing.users")}`,
-          `${plansCompanies.connections} ${i18n.t("checkoutPage.pricing.connection")}`,
-          `${plansCompanies.queues} ${i18n.t("checkoutPage.pricing.queues")}`
-        ],
-        users: plansCompanies.users,
-        connections: plansCompanies.connections,
-        queues: plansCompanies.queues,
-        buttonText: i18n.t("checkoutPage.pricing.SELECT"),
-        buttonVariant: 'outlined',
-      })
-
-      // setStoragePlans(data);
-      //});
-      setStoragePlans(plans);
-    } catch (e) {
-      console.log(e);
-      // toast.error("Não foi possível carregar a lista de registros");
-    }
-    setLoading(false);
-  };
-
-
-  const tiers = storagePlans
-  return (
-    <React.Fragment>
-      <Grid container spacing={3}>
-        {tiers.map((tier) => (
-          // Enterprise card is full width at sm breakpoint
-          <Grid item key={tier.title} xs={12} sm={tier.title === 'Enterprise' ? 12 : 12} md={12}>
-            <Card>
-              <CardHeader
-                title={tier.title}
-                subheader={tier.subheader}
-                titleTypographyProps={{ align: 'center' }}
-                subheaderTypographyProps={{ align: 'center' }}
-                action={tier.title === 'Pro' ? <StarIcon /> : null}
-                className={classes.cardHeader}
-              />
-              <CardContent>
-                <div className={classes.cardPricing}>
-                  <Typography component="h2" variant="h3" color="textPrimary">
-                    {
-
-                      <React.Fragment>
-                        R${tier.price.toLocaleString('pt-br', { minimumFractionDigits: 2 })}
-                      </React.Fragment>
-                    }
-                  </Typography>
-                  <Typography variant="h6" color="textSecondary">
-                    /{i18n.t("checkoutPage.pricing.month")}
-                  </Typography>
-                </div>
-                <ul>
-                  {tier.description.map((line) => (
-                    <Typography component="li" variant="subtitle1" align="center" key={line}>
-                      {line}
-                    </Typography>
-                  ))}
-                </ul>
-              </CardContent>
-              <CardActions>
-                <Button
-                  fullWidth
-                  variant={tier.buttonVariant}
-                  color="primary"
-                  onClick={() => {
-                    if (tier.custom) {
-                      setFieldValue("plan", JSON.stringify({
-                        users: usersPlans,
-                        connections: connectionsPlans,
-                        price: customValuePlans,
-                      }));
-                    } else {
-                      setFieldValue("plan", JSON.stringify(tier));
-                    }
-                    setActiveStep(activeStep + 1);
-                  }
-                  }
-                >
-                  {tier.buttonText}
-                </Button>
-              </CardActions>
-            </Card>
-          </Grid>
-        ))}
-      </Grid>
-    </React.Fragment>
-  );
-}

+ 0 - 61
frontend/src/components/CheckoutPage/ReviewOrder/PaymentDetails.js

@@ -1,61 +0,0 @@
-import React, {useContext} from 'react';
-import { Typography, Grid } from '@material-ui/core';
-import useStyles from './styles';
-import { AuthContext } from "../../../context/Auth/AuthContext";
-
-function PaymentDetails(props) {
-  const { formValues } = props;
-  const classes = useStyles();
-  const { firstName, address2, city, zipcode, state, country, plan } = formValues;
-  const { user } = useContext(AuthContext);
-
-
-  const newPlan = JSON.parse(plan);
-  const { price } = newPlan;
-
-  return (
-    <Grid item container direction="column" xs={12} sm={6}>
-      <Typography variant="h6" gutterBottom className={classes.title}>
-        Informação de pagamento
-      </Typography>
-      <Grid container>
-        <React.Fragment>
-          <Grid item xs={6}>
-            <Typography gutterBottom>Email:</Typography>
-          </Grid>
-          <Grid item xs={6}>
-            <Typography gutterBottom>{user.company.email}</Typography>
-          </Grid>
-        </React.Fragment>
-        <React.Fragment>
-          <Grid item xs={6}>
-            <Typography gutterBottom>Nome:</Typography>
-          </Grid>
-          <Grid item xs={6}>
-            <Typography gutterBottom>{firstName}</Typography>
-          </Grid>
-        </React.Fragment>
-        <React.Fragment>
-          <Grid item xs={6}>
-            <Typography gutterBottom>Endereço:</Typography>
-          </Grid>
-          <Grid item xs={6}>
-            <Typography gutterBottom>
-            {address2}, {city} - {state} {zipcode} {country}
-            </Typography>
-          </Grid>
-        </React.Fragment>
-        <React.Fragment>
-          <Grid item xs={6}>
-            <Typography gutterBottom>Total:</Typography>
-          </Grid>
-          <Grid item xs={6}>
-            <Typography gutterBottom>R${price.toLocaleString('pt-br', {minimumFractionDigits: 2})}</Typography>
-          </Grid>
-        </React.Fragment>
-      </Grid>
-    </Grid>
-  );
-}
-
-export default PaymentDetails;

+ 0 - 33
frontend/src/components/CheckoutPage/ReviewOrder/ProductDetails.js

@@ -1,33 +0,0 @@
-import React from 'react';
-import { Typography, List, ListItem, ListItemText } from '@material-ui/core';
-import useStyles from './styles';
-
-const products = [
-  { name: 'Product 1', desc: 'A nice thing', price: '$9.99' },
-  { name: 'Product 2', desc: 'Another thing', price: '$3.45' },
-  { name: 'Product 3', desc: 'Something else', price: '$6.51' },
-  { name: 'Product 4', desc: 'Best thing of all', price: '$14.11' },
-  { name: 'Shipping', desc: '', price: 'Free' }
-];
-
-function ProductDetails() {
-  const classes = useStyles();
-  return (
-    <List disablePadding>
-      {products.map(product => (
-        <ListItem className={classes.listItem} key={product.name}>
-          <ListItemText primary={product.name} secondary={product.desc} />
-          <Typography variant="body2">{product.price}</Typography>
-        </ListItem>
-      ))}
-      <ListItem className={classes.listItem}>
-        <ListItemText primary="Total" />
-        <Typography variant="subtitle1" className={classes.total}>
-          $34.06
-        </Typography>
-      </ListItem>
-    </List>
-  );
-}
-
-export default ProductDetails;

+ 0 - 20
frontend/src/components/CheckoutPage/ReviewOrder/ReviewOrder.js

@@ -1,20 +0,0 @@
-import React from 'react';
-import { useFormikContext } from 'formik';
-import { Typography, Grid } from '@material-ui/core';
-import ShippingDetails from './ShippingDetails';
-import PaymentDetails from './PaymentDetails';
-import { i18n } from '../../../translate/i18n';
-
-export default function ReviewOrder() {
-  const { values: formValues } = useFormikContext();
-  return (
-    <React.Fragment>
-      <Typography variant="h6" gutterBottom>
-        {i18n.t('checkoutPage.review.title')}
-      </Typography>
-      <Grid container spacing={2}>
-        <ShippingDetails formValues={formValues} />
-      </Grid>
-    </React.Fragment>
-  );
-}

+ 0 - 26
frontend/src/components/CheckoutPage/ReviewOrder/ShippingDetails.js

@@ -1,26 +0,0 @@
-import React from 'react';
-import { Typography, Grid } from '@material-ui/core';
-import useStyles from './styles';
-import { i18n } from '../../../translate/i18n';
-
-function PaymentDetails(props) {
-  const { formValues } = props;
-  const classes = useStyles();
-  const { plan } = formValues;
-
-  const newPlan = JSON.parse(plan);
-  const { users, connections, price } = newPlan;
-  return (
-    <Grid item xs={12} sm={12}>
-      <Typography variant="h6" gutterBottom className={classes.title}>
-        {i18n.t('checkoutPage.review.details')}
-      </Typography>
-      <Typography gutterBottom>{i18n.t('checkoutPage.review.users')}: {users}</Typography>
-      <Typography gutterBottom>{i18n.t('checkoutPage.review.whatsapp')}: {connections}</Typography>
-      <Typography gutterBottom>{i18n.t('checkoutPage.review.charges')}</Typography>
-      <Typography gutterBottom>{i18n.t('checkoutPage.review.total')}: R${price.toLocaleString('pt-br', {minimumFractionDigits: 2})}</Typography>
-    </Grid>
-  );
-}
-
-export default PaymentDetails;

+ 0 - 2
frontend/src/components/CheckoutPage/ReviewOrder/index.js

@@ -1,2 +0,0 @@
-import ReviewOrder from './ReviewOrder';
-export default ReviewOrder;

+ 0 - 12
frontend/src/components/CheckoutPage/ReviewOrder/styles.js

@@ -1,12 +0,0 @@
-import { makeStyles } from '@material-ui/core/styles';
-export default makeStyles(theme => ({
-  listItem: {
-    padding: theme.spacing(1, 0)
-  },
-  total: {
-    fontWeight: '700'
-  },
-  title: {
-    marginTop: theme.spacing(2)
-  }
-}));

+ 0 - 2
frontend/src/components/CheckoutPage/index.js

@@ -1,2 +0,0 @@
-import CheckoutPage from './CheckoutPage';
-export default CheckoutPage;

+ 0 - 23
frontend/src/components/CheckoutPage/styles.js

@@ -1,23 +0,0 @@
-import { makeStyles } from '@material-ui/core/styles';
-export default makeStyles(theme => ({
-  stepper: {
-    padding: theme.spacing(3, 0, 5)
-  },
-  buttons: {
-    display: 'flex',
-    justifyContent: 'flex-end'
-  },
-  button: {
-    marginTop: theme.spacing(3),
-    marginLeft: theme.spacing(1)
-  },
-  wrapper: {
-    margin: theme.spacing(1),
-    position: 'relative'
-  },
-  buttonProgress: {
-    position: 'absolute',
-    top: '50%',
-    left: '50%'
-  }
-}));

+ 0 - 85
frontend/src/components/ColorPicker/index.js

@@ -1,85 +0,0 @@
-import { Dialog } from "@material-ui/core";
-import React, { useState } from "react";
-
-import { BlockPicker } from "react-color";
-
-const ColorPicker = ({ onChange, currentColor, handleClose, open }) => {
-	const [selectedColor, setSelectedColor] = useState(currentColor);
-
-	const handleChange = color => {
-		setSelectedColor(color.hex);
-		handleClose();
-	};
-
-	const colors = [
-		"#B80000",
-		"#DB3E00",
-		"#FCCB00",
-		"#008B02",
-		"#006B76",
-		"#1273DE",
-		"#004DCF",
-		"#5300EB",
-		"#EB9694",
-		"#FAD0C3",
-		"#FEF3BD",
-		"#C1E1C5",
-		"#BEDADC",
-		"#C4DEF6",
-		"#BED3F3",
-		"#D4C4FB",
-		"#4D4D4D",
-		"#999999",
-		"#F44E3B",
-		"#FE9200",
-		"#FCDC00",
-		"#DBDF00",
-		"#A4DD00",
-		"#68CCCA",
-		"#73D8FF",
-		"#AEA1FF",
-		"#FDA1FF",
-		"#333333",
-		"#808080",
-		"#cccccc",
-		"#D33115",
-		"#E27300",
-		"#FCC400",
-		"#B0BC00",
-		"#68BC00",
-		"#16A5A5",
-		"#009CE0",
-		"#7B64FF",
-		"#FA28FF",
-		"#666666",
-		"#B3B3B3",
-		"#9F0500",
-		"#C45100",
-		"#FB9E00",
-		"#808900",
-		"#194D33",
-		"#0C797D",
-		"#0062B1",
-		"#653294",
-		"#AB149E",
-	];
-
-	return (
-		<Dialog
-			onClose={handleClose}
-			aria-labelledby="simple-dialog-title"
-			open={open}
-		>
-			<BlockPicker
-				width={"100%"}
-				triangle="hide"
-				color={selectedColor}
-				colors={colors}
-				onChange={handleChange}
-				onChangeComplete={color => onChange(color.hex)}
-			/>
-		</Dialog>
-	);
-};
-
-export default ColorPicker;

+ 0 - 634
frontend/src/components/CompaniesManager/index.js

@@ -1,634 +0,0 @@
-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";
-import { i18n } from "../../translate/i18n";
-
-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={i18n.t("settings.company.form.name")}
-                  name="name"
-                  variant="outlined"
-                  className={classes.fullWidth}
-                  margin="dense"
-                />
-              </Grid>
-              <Grid xs={12} sm={6} md={2} item>
-                <Field
-                  as={TextField}
-                  label={i18n.t("settings.company.form.email")}
-                  name="email"
-                  variant="outlined"
-                  className={classes.fullWidth}
-                  margin="dense"
-                  required
-                />
-              </Grid>
-              <Grid xs={12} sm={6} md={2} item>
-                <Field
-                  as={TextField}
-                  label={i18n.t("settings.company.form.phone")}
-                  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">
-                    {i18n.t("settings.company.form.plan")}
-                  </InputLabel>
-                  <Field
-                    as={Select}
-                    id="plan-selection"
-                    label={i18n.t("settings.company.form.plan")}
-                    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">
-                    {i18n.t("settings.company.form.status")}
-                  </InputLabel>
-                  <Field
-                    as={Select}
-                    id="status-selection"
-                    label={i18n.t("settings.company.form.status")}
-                    labelId="status-selection-label"
-                    name="status"
-                    margin="dense"
-                  >
-                    <MenuItem value={true}>{i18n.t("settings.company.form.yes")}</MenuItem>
-                    <MenuItem value={false}>{i18n.t("settings.company.form.no")}</MenuItem>
-                  </Field>
-                </FormControl>
-              </Grid>
-              <Grid xs={12} sm={6} md={2} item>
-                <FormControl margin="dense" variant="outlined" fullWidth>
-                  <InputLabel htmlFor="status-selection">{i18n.t("settings.company.form.campanhas")}</InputLabel>
-                  <Field
-                    as={Select}
-                    id="campaigns-selection"
-                    label={i18n.t("settings.company.form.campanhas")}
-                    labelId="campaigns-selection-label"
-                    name="campaignsEnabled"
-                    margin="dense"
-                  >
-                    <MenuItem value={true}>{i18n.t("settings.company.form.enabled")}</MenuItem>
-                    <MenuItem value={false}>{i18n.t("settings.company.form.disabled")}</MenuItem>
-                  </Field>
-                </FormControl>
-              </Grid>
-              <Grid xs={12} sm={6} md={2} item>
-                <FormControl variant="outlined" fullWidth>
-                  <Field
-                    as={TextField}
-                    label={i18n.t("settings.company.form.dueDate")}
-                    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">
-                    {i18n.t("settings.company.form.recurrence")}
-                  </InputLabel>
-                  <Field
-                    as={Select}
-                    label={i18n.t("settings.company.form.recurrence")}
-                    labelId="recorrencia-selection-label"
-                    id="recurrence"
-                    name="recurrence"
-                    margin="dense"
-                  >
-                    <MenuItem value="MENSAL">{i18n.t("settings.company.form.monthly")}</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"
-                    >
-                      {i18n.t("settings.company.buttons.clear")}
-                    </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"
-                        >
-                          {i18n.t("settings.company.buttons.delete")}
-                        </ButtonWithSpinner>
-                      </Grid>
-                      <Grid xs={6} md={2} item>
-                        <ButtonWithSpinner
-                          style={{ marginTop: 7 }}
-                          className={classes.fullWidth}
-                          loading={loading}
-                          onClick={() => incrementDueDate()}
-                          variant="contained"
-                          color="primary"
-                        >
-                          {i18n.t("settings.company.buttons.expire")}
-                        </ButtonWithSpinner>
-                      </Grid>
-                      <Grid xs={6} md={1} item>
-                        <ButtonWithSpinner
-                          style={{ marginTop: 7 }}
-                          className={classes.fullWidth}
-                          loading={loading}
-                          onClick={() => handleOpenModalUsers()}
-                          variant="contained"
-                          color="primary"
-                        >
-                          {i18n.t("settings.company.buttons.user")}
-                        </ButtonWithSpinner>
-                      </Grid>
-                    </>
-                  ) : null}
-                  <Grid xs={6} md={1} item>
-                    <ButtonWithSpinner
-                      className={classes.fullWidth}
-                      style={{ marginTop: 7 }}
-                      loading={loading}
-                      type="submit"
-                      variant="contained"
-                      color="primary"
-                    >
-                      {i18n.t("settings.company.buttons.save")}
-                    </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" ? i18n.t("settings.company.form.enabled") : i18n.t("settings.company.form.disabled");
-      }
-    }
-    return i18n.t("settings.company.form.disabled")
-  };
-
-  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">{i18n.t("settings.company.form.name")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.email")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.phone")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.plan")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.campanhas")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.status")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.createdAt")}</TableCell>
-            <TableCell align="left">{i18n.t("settings.company.form.expire")}</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(i18n.t("settings.company.toasts.errorList"));
-    }
-    setLoading(false);
-  };
-
-  const handleSubmit = async (data) => {
-    setLoading(true);
-    try {
-      if (data.id !== 0 && data.id !== undefined) {
-        await update(data);
-      } else {
-        await save(data);
-      }
-
-      await loadPlans();
-      handleCancel();
-      toast.success(i18n.t("settings.company.toasts.success"));
-    } catch (e) {
-      toast.error(
-        i18n.t("settings.company.toasts.error")
-      );
-    }
-    setLoading(false);
-  };
-
-  const handleDelete = async () => {
-    setLoading(true);
-    try {
-      await remove(record.id);
-      await loadPlans();
-      handleCancel();
-      toast.success(i18n.t("settings.company.toasts.success"));
-    } catch (e) {
-      toast.error(i18n.t("settings.company.toasts.errorOperation"));
-    }
-    setLoading(false);
-  };
-
-  const handleOpenDeleteDialog = () => {
-    setShowConfirmDialog(true);
-  };
-
-  const handleCancel = () => {
-    setRecord((prev) => ({
-      ...prev,
-      id: undefined,
-      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={i18n.t("settings.company.confirmModal.title")}
-        open={showConfirmDialog}
-        onClose={() => setShowConfirmDialog(false)}
-        onConfirm={() => handleDelete()}
-      >
-        {i18n.t("settings.company.confirmModal.message")}
-      </ConfirmationModal>
-    </Paper>
-  );
-}

+ 0 - 45
frontend/src/components/ConfirmationModal/index.js

@@ -1,45 +0,0 @@
-import React from "react";
-import Button from "@material-ui/core/Button";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import Typography from "@material-ui/core/Typography";
-
-import { i18n } from "../../translate/i18n";
-
-const ConfirmationModal = ({ title, children, open, onClose, onConfirm }) => {
-	return (
-		<Dialog
-			open={open}
-			onClose={() => onClose(false)}
-			aria-labelledby="confirm-dialog"
-		>
-			<DialogTitle id="confirm-dialog">{title}</DialogTitle>
-			<DialogContent dividers>
-				<Typography>{children}</Typography>
-			</DialogContent>
-			<DialogActions>
-				<Button
-					variant="contained"
-					onClick={() => onClose(false)}
-					color="default"
-				>
-					{i18n.t("confirmationModal.buttons.cancel")}
-				</Button>
-				<Button
-					variant="contained"
-					onClick={() => {
-						onClose(false);
-						onConfirm();
-					}}
-					color="secondary"
-				>
-					{i18n.t("confirmationModal.buttons.confirm")}
-				</Button>
-			</DialogActions>
-		</Dialog>
-	);
-};
-
-export default ConfirmationModal;

+ 0 - 199
frontend/src/components/ContactDrawer/index.js

@@ -1,199 +0,0 @@
-import React, { useEffect, useState } from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-import Typography from "@material-ui/core/Typography";
-import IconButton from "@material-ui/core/IconButton";
-import CloseIcon from "@material-ui/icons/Close";
-import Drawer from "@material-ui/core/Drawer";
-import Link from "@material-ui/core/Link";
-import InputLabel from "@material-ui/core/InputLabel";
-import Avatar from "@material-ui/core/Avatar";
-import Button from "@material-ui/core/Button";
-import Paper from "@material-ui/core/Paper";
-import CreateIcon from '@material-ui/icons/Create';
-
-import { i18n } from "../../translate/i18n";
-
-import ContactDrawerSkeleton from "../ContactDrawerSkeleton";
-import MarkdownWrapper from "../MarkdownWrapper";
-import { CardHeader } from "@material-ui/core";
-import { ContactForm } from "../ContactForm";
-import ContactModal from "../ContactModal";
-import { ContactNotes } from "../ContactNotes";
-
-const drawerWidth = 320;
-
-const useStyles = makeStyles(theme => ({
-	drawer: {
-		width: drawerWidth,
-		flexShrink: 0,
-	},
-	drawerPaper: {
-		width: drawerWidth,
-		display: "flex",
-		borderTop: "1px solid rgba(0, 0, 0, 0.12)",
-		borderRight: "1px solid rgba(0, 0, 0, 0.12)",
-		borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
-		borderTopRightRadius: 4,
-		borderBottomRightRadius: 4,
-	},
-	header: {
-		display: "flex",
-		borderBottom: "1px solid rgba(0, 0, 0, 0.12)",
-		backgroundColor: theme.palette.contactdrawer, //DARK MODE PLW DESIGN//
-		alignItems: "center",
-		padding: theme.spacing(0, 1),
-		minHeight: "73px",
-		justifyContent: "flex-start",
-	},
-	content: {
-		display: "flex",
-		backgroundColor: theme.palette.contactdrawer, //DARK MODE PLW DESIGN//
-		flexDirection: "column",
-		padding: "8px 0px 8px 8px",
-		height: "100%",
-		overflowY: "scroll",
-		...theme.scrollbarStyles,
-	},
-
-	contactAvatar: {
-		margin: 15,
-		width: 100,
-		height: 100,
-	},
-
-	contactHeader: {
-		display: "flex",
-		padding: 8,
-		flexDirection: "column",
-		alignItems: "center",
-		justifyContent: "center",
-		"& > *": {
-			margin: 4,
-		},
-	},
-
-	contactDetails: {
-		marginTop: 8,
-		padding: 8,
-		display: "flex",
-		flexDirection: "column",
-	},
-	contactExtraInfo: {
-		marginTop: 4,
-		padding: 6,
-	},
-}));
-
-const ContactDrawer = ({ open, handleDrawerClose, contact, ticket, loading }) => {
-	const classes = useStyles();
-
-	const [modalOpen, setModalOpen] = useState(false);
-	const [openForm, setOpenForm] = useState(false);
-
-	useEffect(() => {
-		setOpenForm(false);
-	}, [open, contact]);
-
-	return (
-		<>
-			<Drawer
-				className={classes.drawer}
-				variant="persistent"
-				anchor="right"
-				open={open}
-				PaperProps={{ style: { position: "absolute" } }}
-				BackdropProps={{ style: { position: "absolute" } }}
-				ModalProps={{
-					container: document.getElementById("drawer-container"),
-					style: { position: "absolute" },
-				}}
-				classes={{
-					paper: classes.drawerPaper,
-				}}
-			>
-				<div className={classes.header}>
-					<IconButton onClick={handleDrawerClose}>
-						<CloseIcon />
-					</IconButton>
-					<Typography style={{ justifySelf: "center" }}>
-						{i18n.t("contactDrawer.header")}
-					</Typography>
-				</div>
-				{loading ? (
-					<ContactDrawerSkeleton classes={classes} />
-				) : (
-					<div className={classes.content}>
-						<Paper square variant="outlined" className={classes.contactHeader}>
-							<CardHeader
-								onClick={() => {}}
-								style={{ cursor: "pointer", width: '100%' }}
-								titleTypographyProps={{ noWrap: true }}
-								subheaderTypographyProps={{ noWrap: true }}
-								avatar={<Avatar src={contact.profilePicUrl} alt="contact_image" style={{ width: 60, height: 60 }} />}
-								title={
-									<>
-										<Typography onClick={() => setOpenForm(true)}>
-											{contact.name}
-											<CreateIcon style={{fontSize: 16, marginLeft: 5}} />
-										</Typography>
-									</>
-								}
-								subheader={
-									<>
-										<Typography style={{fontSize: 12}}>
-											<Link href={`tel:${contact.number}`}>{contact.number}</Link>
-										</Typography>
-										<Typography style={{fontSize: 12}}>
-											<Link href={`mailto:${contact.email}`}>{contact.email}</Link>
-										</Typography>
-									</>
-								}
-							/>
-							<Button
-								variant="outlined"
-								color="primary"
-								onClick={() => setModalOpen(!openForm)}
-								style={{fontSize: 12}}
-							>
-								{i18n.t("contactDrawer.buttons.edit")}
-							</Button>
-							{(contact.id && openForm) && <ContactForm initialContact={contact} onCancel={() => setOpenForm(false)} />}
-						</Paper>
-						<Paper square variant="outlined" className={classes.contactDetails}>
-							<Typography variant="subtitle1" style={{marginBottom: 10}}>
-								{i18n.t("ticketOptionsMenu.appointmentsModal.title")}
-							</Typography>
-							<ContactNotes ticket={ticket} />
-						</Paper>
-						<Paper square variant="outlined" className={classes.contactDetails}>
-							<ContactModal
-								open={modalOpen}
-								onClose={() => setModalOpen(false)}
-								contactId={contact.id}
-							></ContactModal>
-							<Typography variant="subtitle1">
-								{i18n.t("contactDrawer.extraInfo")}
-							</Typography>
-							{contact?.extraInfo?.map(info => (
-								<Paper
-									key={info.id}
-									square
-									variant="outlined"
-									className={classes.contactExtraInfo}
-								>
-									<InputLabel>{info.name}</InputLabel>
-									<Typography component="div" noWrap style={{ paddingTop: 2 }}>
-										<MarkdownWrapper>{info.value}</MarkdownWrapper>
-									</Typography>
-								</Paper>
-							))}
-						</Paper>
-					</div>
-				)}
-			</Drawer>
-		</>
-	);
-};
-
-export default ContactDrawer;

+ 0 - 50
frontend/src/components/ContactDrawerSkeleton/index.js

@@ -1,50 +0,0 @@
-import React from "react";
-import Skeleton from "@material-ui/lab/Skeleton";
-import Typography from "@material-ui/core/Typography";
-import Paper from "@material-ui/core/Paper";
-import { i18n } from "../../translate/i18n";
-import { Grid } from "@material-ui/core";
-
-const ContactDrawerSkeleton = ({ classes }) => {
-	return (
-		<div className={classes.content}>
-			<Paper square variant="outlined" className={classes.contactHeader}>
-				<Grid container>
-					<Grid item>
-						<Skeleton
-							animation="wave"
-							variant="circle"
-							width={60}
-							height={60}
-							className={classes.contactAvatar}
-						/>
-					</Grid>
-					<Grid item>
-						<Skeleton animation="wave" height={25} width={90} />
-						<Skeleton animation="wave" height={25} width={80} />
-						<Skeleton animation="wave" height={25} width={80} />
-					</Grid>
-				</Grid>
-			</Paper>
-			<Paper square className={classes.contactDetails}>
-				<Typography variant="subtitle1">
-					{i18n.t("contactDrawer.extraInfo")}
-				</Typography>
-				<Paper square variant="outlined" className={classes.contactExtraInfo}>
-					<Skeleton animation="wave" height={20} width={60} />
-					<Skeleton animation="wave" height={20} width={160} />
-				</Paper>
-				<Paper square variant="outlined" className={classes.contactExtraInfo}>
-					<Skeleton animation="wave" height={20} width={60} />
-					<Skeleton animation="wave" height={20} width={160} />
-				</Paper>
-				<Paper square variant="outlined" className={classes.contactExtraInfo}>
-					<Skeleton animation="wave" height={20} width={60} />
-					<Skeleton animation="wave" height={20} width={160} />
-				</Paper>
-			</Paper>
-		</div>
-	);
-};
-
-export default ContactDrawerSkeleton;

+ 0 - 187
frontend/src/components/ContactForm/index.js

@@ -1,187 +0,0 @@
-import React, { useState, useEffect } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { Grid } from "@material-ui/core";
-
-const useStyles = makeStyles(theme => ({
-	root: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	textField: {
-		marginRight: theme.spacing(1),
-		flex: 1,
-	},
-
-	extraAttr: {
-		display: "flex",
-		justifyContent: "center",
-		alignItems: "center",
-	},
-
-	btnWrapper: {
-		position: "relative",
-	},
-
-	buttonProgress: {
-		color: green[500],
-		position: "absolute",
-		top: "50%",
-		left: "50%",
-		marginTop: -12,
-		marginLeft: -12,
-	},
-
-    textCenter: {
-        backgroundColor: 'red'
-    }
-}));
-
-const ContactSchema = Yup.object().shape({
-	name: Yup.string()
-		.min(2, "Too Short!")
-		.max(50, "Too Long!")
-		.required("Required"),
-	number: Yup.string().min(8, "Too Short!").max(50, "Too Long!"),
-	email: Yup.string().email("Invalid email"),
-});
-
-export function ContactForm ({ initialContact, onSave, onCancel }) {
-	const classes = useStyles();
-
-	const [contact, setContact] = useState(initialContact);
-
-    useEffect(() => {
-        setContact(initialContact);
-    }, [initialContact]);
-
-	const handleSaveContact = async values => {
-		try {
-			if (contact.id) {
-				await api.put(`/contacts/${contact.id}`, values);
-			} else {
-				const { data } = await api.post("/contacts", values);
-				if (onSave) {
-					onSave(data);
-				}
-			}
-			toast.success(i18n.t("contactModal.success"));
-		} catch (err) {
-			toastError(err);
-		}
-	};
-
-    return (
-        <Formik
-            initialValues={contact}
-            enableReinitialize={true}
-            validationSchema={ContactSchema}
-            onSubmit={(values, actions) => {
-                setTimeout(() => {
-                    handleSaveContact(values);
-                    actions.setSubmitting(false);
-                }, 400);
-            }}
-        >
-            {({ values, errors, touched, isSubmitting }) => (
-                <Form>
-                    <Grid container spacing={1}>
-                        {/* <Grid item xs={12}>
-                            <Typography variant="subtitle1" gutterBottom>
-                                {i18n.t("contactModal.form.mainInfo")}
-                            </Typography>
-                        </Grid> */}
-                        <Grid item xs={12}>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("contactModal.form.name")}
-                                name="name"
-                                autoFocus
-                                error={touched.name && Boolean(errors.name)}
-                                helperText={touched.name && errors.name}
-                                variant="outlined"
-                                margin="dense"
-                                className={classes.textField}
-                                fullWidth
-                            />
-                        </Grid>
-                        <Grid item xs={12}>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("contactModal.form.number")}
-                                name="number"
-                                error={touched.number && Boolean(errors.number)}
-                                helperText={touched.number && errors.number}
-                                placeholder="5513912344321"
-                                variant="outlined"
-                                margin="dense"
-                                fullWidth
-                            />
-                        </Grid>
-                        <Grid item xs={12}>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("contactModal.form.email")}
-                                name="email"
-                                error={touched.email && Boolean(errors.email)}
-                                helperText={touched.email && errors.email}
-                                placeholder="Email address"
-                                fullWidth
-                                margin="dense"
-                                variant="outlined"
-                            />
-                        </Grid>
-                        <Grid item xs={12} spacing={1}>
-                            <Grid container spacing={1}>
-                                <Grid xs={6} item>
-                                    <Button
-                                        onClick={onCancel}
-                                        color="secondary"
-                                        disabled={isSubmitting}
-                                        variant="outlined"
-                                        fullWidth
-                                    >
-                                        {i18n.t("contactModal.buttons.cancel")}
-                                    </Button>
-                                </Grid>
-                                <Grid classes={classes.textCenter} xs={6} item>
-                                    <Button
-                                        type="submit"
-                                        color="primary"
-                                        disabled={isSubmitting}
-                                        variant="contained"
-                                        className={classes.btnWrapper}
-                                        fullWidth
-                                    >
-                                        {contact.id
-                                            ? `${i18n.t("contactModal.buttons.okEdit")}`
-                                            : `${i18n.t("contactModal.buttons.okAdd")}`}
-                                        {isSubmitting && (
-                                            <CircularProgress
-                                                size={24}
-                                                className={classes.buttonProgress}
-                                            />
-                                        )}
-                                    </Button>
-                                </Grid>
-                            </Grid>
-                        </Grid>
-                    </Grid>
-                </Form>
-            )}
-        </Formik>
-    )
-}

+ 0 - 181
frontend/src/components/ContactListDialog/index.js

@@ -1,181 +0,0 @@
-import React, { useState, useEffect } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-
-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,
-  },
-  formControl: {
-    margin: theme.spacing(1),
-    minWidth: 120,
-  },
-}));
-
-const ContactListSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, i18n.t("contactLists.dialog.nameShort"))
-    .max(50, i18n.t("contactLists.dialog.nameLong"))
-    .required(i18n.t("contactLists.dialog.nameRequired")),
-});
-
-const ContactListModal = ({ open, onClose, contactListId }) => {
-  const classes = useStyles();
-
-  const initialState = {
-    name: "",
-  };
-
-  const [contactList, setContactList] = useState(initialState);
-
-  useEffect(() => {
-    const fetchContactList = async () => {
-      if (!contactListId) return;
-      try {
-        const { data } = await api.get(`/contact-lists/${contactListId}`);
-        setContactList((prevState) => {
-          return { ...prevState, ...data };
-        });
-      } catch (err) {
-        toastError(err);
-      }
-    };
-
-    fetchContactList();
-  }, [contactListId, open]);
-
-  const handleClose = () => {
-    onClose();
-    setContactList(initialState);
-  };
-
-  const handleSaveContactList = async (values) => {
-    const contactListData = { ...values };
-    try {
-      if (contactListId) {
-        await api.put(`/contact-lists/${contactListId}`, contactListData);
-      } else {
-        await api.post("/contact-lists", contactListData);
-      }
-      toast.success(i18n.t("contactList.toasts.success"));
-    } catch (err) {
-      toastError(err);
-    }
-    handleClose();
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog
-        open={open}
-        onClose={handleClose}
-        maxWidth="xs"
-        fullWidth
-        scroll="paper"
-      >
-        <DialogTitle id="form-dialog-title">
-          {contactListId
-            ? `${i18n.t("contactLists.dialog.edit")}`
-            : `${i18n.t("contactLists.dialog.add")}`}
-        </DialogTitle>
-        <Formik
-          initialValues={contactList}
-          enableReinitialize={true}
-          validationSchema={ContactListSchema}
-          onSubmit={(values, actions) => {
-            setTimeout(() => {
-              handleSaveContactList(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ touched, errors, isSubmitting }) => (
-            <Form>
-              <DialogContent dividers>
-                <div className={classes.multFieldLine}>
-                  <Field
-                    as={TextField}
-                    label={i18n.t("contactLists.dialog.name")}
-                    autoFocus
-                    name="name"
-                    error={touched.name && Boolean(errors.name)}
-                    helperText={touched.name && errors.name}
-                    variant="outlined"
-                    margin="dense"
-                    fullWidth
-                  />
-                </div>
-              </DialogContent>
-              <DialogActions>
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("contactLists.dialog.cancel")}
-                </Button>
-                <Button
-                  type="submit"
-                  color="primary"
-                  disabled={isSubmitting}
-                  variant="contained"
-                  className={classes.btnWrapper}
-                >
-                  {contactListId
-                    ? `${i18n.t("contactLists.dialog.okEdit")}`
-                    : `${i18n.t("contactLists.dialog.okAdd")}`}
-                  {isSubmitting && (
-                    <CircularProgress
-                      size={24}
-                      className={classes.buttonProgress}
-                    />
-                  )}
-                </Button>
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div>
-  );
-};
-
-export default ContactListModal;

+ 0 - 242
frontend/src/components/ContactListItemModal/index.js

@@ -1,242 +0,0 @@
-import React, { useState, useEffect, useRef, useContext } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import Typography from "@material-ui/core/Typography";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { useParams } from "react-router-dom";
-import { AuthContext } from "../../context/Auth/AuthContext";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: "flex",
-    flexWrap: "wrap",
-  },
-  textField: {
-    marginRight: theme.spacing(1),
-    flex: 1,
-  },
-
-  extraAttr: {
-    display: "flex",
-    justifyContent: "center",
-    alignItems: "center",
-  },
-
-  btnWrapper: {
-    position: "relative",
-  },
-
-  buttonProgress: {
-    color: green[500],
-    position: "absolute",
-    top: "50%",
-    left: "50%",
-    marginTop: -12,
-    marginLeft: -12,
-  },
-}));
-
-const ContactSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, i18n.t("contactListItems.dialog.nameShort"))
-    .max(50, i18n.t("contactListItems.dialog.nameLong"))
-    .required(i18n.t("contactListItems.dialog.nameRequired")),
-  number: Yup.string().min(8, i18n.t("contactListItems.dialog.numberShort")).max(50, i18n.t("contactListItems.dialog.numberLong")),
-  email: Yup.string().email(i18n.t("contactListItems.dialog.emailInvalid")),
-});
-
-const ContactListItemModal = ({
-  open,
-  onClose,
-  contactId,
-  initialValues,
-  onSave,
-}) => {
-  const classes = useStyles();
-  const isMounted = useRef(true);
-
-  const {
-    user: { companyId },
-  } = useContext(AuthContext);
-  const { contactListId } = useParams();
-
-  const initialState = {
-    name: "",
-    number: "",
-    email: "",
-  };
-
-  const [contact, setContact] = useState(initialState);
-
-  useEffect(() => {
-    return () => {
-      isMounted.current = false;
-    };
-  }, []);
-
-  useEffect(() => {
-    const fetchContact = async () => {
-      if (initialValues) {
-        setContact((prevState) => {
-          return { ...prevState, ...initialValues };
-        });
-      }
-
-      if (!contactId) return;
-
-      try {
-        const { data } = await api.get(`/contact-list-items/${contactId}`);
-        if (isMounted.current) {
-          setContact(data);
-        }
-      } catch (err) {
-        toastError(err);
-      }
-    };
-
-    fetchContact();
-  }, [contactId, open, initialValues]);
-
-  const handleClose = () => {
-    onClose();
-    setContact(initialState);
-  };
-
-  const handleSaveContact = async (values) => {
-    try {
-      if (contactId) {
-        await api.put(`/contact-list-items/${contactId}`, {
-          ...values,
-          companyId,
-          contactListId,
-        });
-        handleClose();
-      } else {
-        const { data } = await api.post("/contact-list-items", {
-          ...values,
-          companyId,
-          contactListId,
-        });
-        if (onSave) {
-          onSave(data);
-        }
-        handleClose();
-      }
-      toast.success(i18n.t("contactModal.success"));
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog open={open} onClose={handleClose} maxWidth="lg" scroll="paper">
-        <DialogTitle id="form-dialog-title">
-          {contactId
-            ? `${i18n.t("contactModal.title.edit")}`
-            : `${i18n.t("contactModal.title.add")}`}
-        </DialogTitle>
-        <Formik
-          initialValues={contact}
-          enableReinitialize={true}
-          validationSchema={ContactSchema}
-          onSubmit={(values, actions) => {
-            setTimeout(() => {
-              handleSaveContact(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ values, errors, touched, isSubmitting }) => (
-            <Form>
-              <DialogContent dividers>
-                <Typography variant="subtitle1" gutterBottom>
-                  {i18n.t("contactModal.form.mainInfo")}
-                </Typography>
-                <Field
-                  as={TextField}
-                  label={i18n.t("contactModal.form.name")}
-                  name="name"
-                  autoFocus
-                  error={touched.name && Boolean(errors.name)}
-                  helperText={touched.name && errors.name}
-                  variant="outlined"
-                  margin="dense"
-                  className={classes.textField}
-                />
-                <Field
-                  as={TextField}
-                  label={i18n.t("contactModal.form.number")}
-                  name="number"
-                  error={touched.number && Boolean(errors.number)}
-                  helperText={touched.number && errors.number}
-                  placeholder="5513912344321"
-                  variant="outlined"
-                  margin="dense"
-                />
-                <div>
-                  <Field
-                    as={TextField}
-                    label={i18n.t("contactModal.form.email")}
-                    name="email"
-                    error={touched.email && Boolean(errors.email)}
-                    helperText={touched.email && errors.email}
-                    placeholder={i18n.t("contactModal.form.email")}
-                    fullWidth
-                    margin="dense"
-                    variant="outlined"
-                  />
-                </div>
-              </DialogContent>
-              <DialogActions>
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("contactModal.buttons.cancel")}
-                </Button>
-                <Button
-                  type="submit"
-                  color="primary"
-                  disabled={isSubmitting}
-                  variant="contained"
-                  className={classes.btnWrapper}
-                >
-                  {contactId
-                    ? `${i18n.t("contactModal.buttons.okEdit")}`
-                    : `${i18n.t("contactModal.buttons.okAdd")}`}
-                  {isSubmitting && (
-                    <CircularProgress
-                      size={24}
-                      className={classes.buttonProgress}
-                    />
-                  )}
-                </Button>
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div>
-  );
-};
-
-export default ContactListItemModal;

+ 0 - 103
frontend/src/components/ContactListTable/index.js

@@ -1,103 +0,0 @@
-import React, { useState, useEffect } from "react";
-import PropTypes from "prop-types";
-import {
-  Table,
-  TableHead,
-  TableBody,
-  TableCell,
-  TableRow,
-  IconButton,
-} from "@material-ui/core";
-import {
-  Edit as EditIcon,
-  DeleteOutline as DeleteOutlineIcon,
-  People as PeopleIcon,
-} from "@material-ui/icons";
-
-import TableRowSkeleton from "../../components/TableRowSkeleton";
-
-function ContactListsTable(props) {
-  const {
-    contactLists,
-    showLoading,
-    editContactList,
-    deleteContactList,
-    readOnly,
-  } = props;
-  const [loading, setLoading] = useState(true);
-  const [rows, setRows] = useState([]);
-
-  useEffect(() => {
-    if (Array.isArray(contactLists)) {
-      setRows(contactLists);
-    }
-    if (showLoading !== undefined) {
-      setLoading(showLoading);
-    }
-  }, [contactLists, showLoading]);
-
-  const handleEdit = (contactList) => {
-    editContactList(contactList);
-  };
-
-  const handleDelete = (contactList) => {
-    deleteContactList(contactList);
-  };
-
-  const renderRows = () => {
-    return rows.map((contactList) => {
-      return (
-        <TableRow key={contactList.id}>
-          <TableCell align="left">{contactList.name}</TableCell>
-          <TableCell align="center"></TableCell>
-          {!readOnly ? (
-            <TableCell align="center">
-              <IconButton size="small">
-                <PeopleIcon />
-              </IconButton>
-
-              <IconButton size="small" onClick={() => handleEdit(contactList)}>
-                <EditIcon />
-              </IconButton>
-
-              <IconButton
-                size="small"
-                onClick={() => handleDelete(contactList)}
-              >
-                <DeleteOutlineIcon />
-              </IconButton>
-            </TableCell>
-          ) : null}
-        </TableRow>
-      );
-    });
-  };
-
-  return (
-    <Table size="small">
-      <TableHead>
-        <TableRow>
-          <TableCell align="left">Nome</TableCell>
-          <TableCell align="center">Contatos</TableCell>
-          {!readOnly ? <TableCell align="center">Ações</TableCell> : null}
-        </TableRow>
-      </TableHead>
-      <TableBody>
-        {loading ? (
-          <TableRowSkeleton columns={readOnly ? 2 : 3} />
-        ) : (
-          renderRows()
-        )}
-      </TableBody>
-    </Table>
-  );
-}
-
-ContactListsTable.propTypes = {
-  contactLists: PropTypes.array.isRequired,
-  showLoading: PropTypes.bool,
-  editContactList: PropTypes.func.isRequired,
-  deleteContactList: PropTypes.func.isRequired,
-};
-
-export default ContactListsTable;

+ 0 - 300
frontend/src/components/ContactModal/index.js

@@ -1,300 +0,0 @@
-import React, { useState, useEffect, useRef } from "react";
-
-import * as Yup from "yup";
-import { Formik, FieldArray, Form, Field } from "formik";
-import { toast } from "react-toastify";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import Typography from "@material-ui/core/Typography";
-import IconButton from "@material-ui/core/IconButton";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-
-import InputMask from 'react-input-mask';
-
-const useStyles = makeStyles(theme => ({
-	root: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	textField: {
-		marginRight: theme.spacing(1),
-		flex: 1,
-	},
-
-	extraAttr: {
-		display: "flex",
-		justifyContent: "center",
-		alignItems: "center",
-	},
-
-	btnWrapper: {
-		position: "relative",
-	},
-
-	buttonProgress: {
-		color: green[500],
-		position: "absolute",
-		top: "50%",
-		left: "50%",
-		marginTop: -12,
-		marginLeft: -12,
-	},
-}));
-
-const MaskedTextField = ({ field, form, ...props }) => {
-	return (
-	  <InputMask {...field} {...props}>
-		{(inputProps) => <TextField {...inputProps} />}
-	  </InputMask>
-	);
-};
-
-const ContactSchema = Yup.object().shape({
-	name: Yup.string()
-		.min(2, i18n.t("contactModal.formErrors.name.short"))
-		.max(50, i18n.t("contactModal.formErrors.name.long"))
-		.required(i18n.t("contactModal.formErrors.name.required")),
-	number: Yup.string().min(8, 
-		i18n.t("contactModal.formErrors.phone.short")).max(50, 
-		i18n.t("contactModal.formErrors.phone.long")),
-	email: Yup.string().email(i18n.t("contactModal.formErrors.email.invalid")),
-});
-
-const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => {
-	const classes = useStyles();
-	const isMounted = useRef(true);
-
-	const initialState = {
-		name: "",
-		number: "",
-		email: "",
-	};
-
-	const [contact, setContact] = useState(initialState);
-
-	useEffect(() => {
-		return () => {
-			isMounted.current = false;
-		};
-	}, []);
-
-	useEffect(() => {
-		const fetchContact = async () => {
-			if (initialValues) {
-				setContact(prevState => {
-					return { ...prevState, ...initialValues };
-				});
-			}
-
-			if (!contactId) return;
-
-			try {
-				const { data } = await api.get(`/contacts/${contactId}`);
-				if (isMounted.current) {
-					console.log(data)
-					setContact({
-						...data,
-						number: data.number,
-					});
-				}
-			} catch (err) {
-				toastError(err);
-			}
-		};
-
-		fetchContact();
-	}, [contactId, open, initialValues]);
-
-	const handleClose = () => {
-		onClose();
-		setContact(initialState);
-	};
-
-	const handleSaveContact = async values => {
-		try {
-			if (contactId) {
-				await api.put(`/contacts/${contactId}`, values);
-				handleClose();
-			} else {
-				const { data } = await api.post("/contacts", values);
-				if (onSave) {
-					onSave(data);
-				}
-				handleClose();
-			}
-			toast.success(i18n.t("contactModal.success"));
-		} catch (e) {	
-			toastError(e);
-		}
-	};
-
-	return (
-		<div className={classes.root}>
-			<Dialog open={open} onClose={handleClose} maxWidth="lg" scroll="paper">
-				<DialogTitle id="form-dialog-title">
-					{contactId
-						? `${i18n.t("contactModal.title.edit")}`
-						: `${i18n.t("contactModal.title.add")}`}
-				</DialogTitle>
-				<Formik
-					initialValues={contact}
-					enableReinitialize={true}
-					validationSchema={ContactSchema}
-					onSubmit={(values, actions) => {
-						setTimeout(() => {
-							handleSaveContact(values);
-							actions.setSubmitting(false);
-						}, 400);
-					}}
-				>
-					{({ values, errors, touched, isSubmitting }) => (
-						<Form>
-							<DialogContent dividers>
-								<Typography variant="subtitle1" gutterBottom>
-									{i18n.t("contactModal.form.mainInfo")}
-								</Typography>
-								<Field
-									as={TextField}
-									label={i18n.t("contactModal.form.name")}
-									name="name"
-									autoFocus
-									error={touched.name && Boolean(errors.name)}
-									helperText={touched.name && errors.name}
-									variant="outlined"
-									margin="dense"
-									className={classes.textField}
-								/>
-								<Field
-									as={TextField}
-									name="number"
-									label={i18n.t("contactModal.form.number")}
-									error={touched.number && Boolean(errors.number)}
-									helperText={touched.number && errors.number}
-									placeholder=""
-									variant="outlined"
-									margin="dense"
-								/>
-
-								<div>
-									<Field
-										as={TextField}
-										label={i18n.t("contactModal.form.email")}
-										name="email"
-										error={touched.email && Boolean(errors.email)}
-										helperText={touched.email && errors.email}
-										placeholder="Email address"
-										fullWidth
-										margin="dense"
-										variant="outlined"
-									/>
-								</div>
-								<Typography
-									style={{ marginBottom: 8, marginTop: 12 }}
-									variant="subtitle1"
-								>
-									{i18n.t("contactModal.form.whatsapp")} {contact?.whatsapp ? contact?.whatsapp.name : ""}
-								</Typography>
-								<Typography
-									style={{ marginBottom: 8, marginTop: 12 }}
-									variant="subtitle1"
-								>
-									{i18n.t("contactModal.form.extraInfo")}
-								</Typography>
-
-								<FieldArray name="extraInfo">
-									{({ push, remove }) => (
-										<>
-											{values.extraInfo &&
-												values.extraInfo.length > 0 &&
-												values.extraInfo.map((info, index) => (
-													<div
-														className={classes.extraAttr}
-														key={`${index}-info`}
-													>
-														<Field
-															as={TextField}
-															label={i18n.t("contactModal.form.extraName")}
-															name={`extraInfo[${index}].name`}
-															variant="outlined"
-															margin="dense"
-															className={classes.textField}
-														/>
-														<Field
-															as={TextField}
-															label={i18n.t("contactModal.form.extraValue")}
-															name={`extraInfo[${index}].value`}
-															variant="outlined"
-															margin="dense"
-															className={classes.textField}
-														/>
-														<IconButton
-															size="small"
-															onClick={() => remove(index)}
-														>
-															<DeleteOutlineIcon />
-														</IconButton>
-													</div>
-												))}
-											<div className={classes.extraAttr}>
-												<Button
-													style={{ flex: 1, marginTop: 8 }}
-													variant="outlined"
-													color="primary"
-													onClick={() => push({ name: "", value: "" })}
-												>
-													{`+ ${i18n.t("contactModal.buttons.addExtraInfo")}`}
-												</Button>
-											</div>
-										</>
-									)}
-								</FieldArray>
-							</DialogContent>
-							<DialogActions>
-								<Button
-									onClick={handleClose}
-									color="secondary"
-									disabled={isSubmitting}
-									variant="outlined"
-								>
-									{i18n.t("contactModal.buttons.cancel")}
-								</Button>
-								<Button
-									type="submit"
-									color="primary"
-									disabled={isSubmitting}
-									variant="contained"
-									className={classes.btnWrapper}
-								>
-									{contactId
-										? `${i18n.t("contactModal.buttons.okEdit")}`
-										: `${i18n.t("contactModal.buttons.okAdd")}`}
-									{isSubmitting && (
-										<CircularProgress
-											size={24}
-											className={classes.buttonProgress}
-										/>
-									)}
-								</Button>
-							</DialogActions>
-						</Form>
-					)}
-				</Formik>
-			</Dialog>
-		</div>
-	);
-};
-
-export default ContactModal;

+ 0 - 204
frontend/src/components/ContactNotes/index.js

@@ -1,204 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import Button from '@material-ui/core/Button';
-import TextField from '@material-ui/core/TextField';
-import List from '@material-ui/core/List';
-import { makeStyles } from '@material-ui/core/styles';
-import * as Yup from "yup";
-import { Formik, Form, Field } from "formik";
-
-import ContactNotesDialogListItem from '../ContactNotesDialogListItem';
-import ConfirmationModal from '../ConfirmationModal';
-
-import { toast } from "react-toastify";
-
-import { i18n } from "../../translate/i18n";
-
-import ButtonWithSpinner from '../ButtonWithSpinner';
-
-import useTicketNotes from '../../hooks/useTicketNotes';
-import { Grid } from '@material-ui/core';
-
-const useStyles = makeStyles((theme) => ({
-    root: {
-        '& .MuiTextField-root': {
-            margin: theme.spacing(1),
-            width: '350px',
-        },
-    },
-    list: {
-        width: '100%',
-        maxWidth: '350px',
-        maxHeight: '200px',
-        backgroundColor: theme.palette.background.paper,
-        overflow: 'auto'
-    },
-    inline: {
-        width: '100%'
-    }
-}));
-
-const NoteSchema = Yup.object().shape({
-	note: Yup.string()
-		.min(2, "Too Short!")
-		.required("Required")
-});
-export function ContactNotes ({ ticket }) {
-    const { id: ticketId, contactId } = ticket
-    const classes = useStyles()
-    const [newNote, setNewNote] = useState({ note: "" });
-    const [loading, setLoading] = useState(false)
-    const [showOnDeleteDialog, setShowOnDeleteDialog] = useState(false)
-    const [selectedNote, setSelectedNote] = useState({})
-    const [notes, setNotes] = useState([])
-    const { saveNote, deleteNote, listNotes } = useTicketNotes()
-
-    useEffect(() => {
-        async function openAndFetchData () {
-            handleResetState()
-            await loadNotes()
-        }
-        openAndFetchData()
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [])
-
-    const handleResetState = () => {
-        setNewNote({ note: "" })
-        setLoading(false)
-    }
-
-    const handleChangeComment = (e) => {
-        setNewNote({ note: e.target.value })
-    }
-
-    const handleSave = async values => {
-        setLoading(true)
-        try {
-            await saveNote({
-                ...values,
-                ticketId,
-                contactId
-            })
-            await loadNotes()
-            setNewNote({ note: '' })
-            toast.success('Observação adicionada com sucesso!')
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const handleOpenDialogDelete = (item) => {
-        setSelectedNote(item)
-        setShowOnDeleteDialog(true)
-    }
-
-    const handleDelete = async () => {
-        setLoading(true)
-        try {
-            await deleteNote(selectedNote.id)
-            await loadNotes()
-            setSelectedNote({})
-            toast.success('Observação excluída com sucesso!')
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const loadNotes = async () => {
-        setLoading(true)
-        try {
-            const notes = await listNotes({ ticketId, contactId })
-            setNotes(notes)
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const renderNoteList = () => {
-        return notes.map((note) => {
-            return <ContactNotesDialogListItem
-                note={note}
-                key={note.id}
-                deleteItem={handleOpenDialogDelete}
-            />
-        })
-    }
-
-    return (
-        <>
-            <ConfirmationModal
-                title="Excluir Registro"
-                open={showOnDeleteDialog}
-                onClose={setShowOnDeleteDialog}
-                onConfirm={handleDelete}
-            >
-                Deseja realmente excluir este registro?
-            </ConfirmationModal>
-            <Formik
-                initialValues={newNote}
-                enableReinitialize={true}
-                validationSchema={NoteSchema}
-                onSubmit={(values, actions) => {
-                    setTimeout(() => {
-                        handleSave(values);
-                        actions.setSubmitting(false);
-                    }, 400);
-                }}
-            >
-
-                {({ touched, errors, setErrors }) => (
-                    <Form>
-                        <Grid container spacing={2}>
-                            <Grid xs={12} item>
-                                <Field
-                                    as={TextField}
-                                    name="note"
-                                    rows={3}
-                                    label={i18n.t("ticketOptionsMenu.appointmentsModal.textarea")}
-                                    placeholder={i18n.t("ticketOptionsMenu.appointmentsModal.placeholder")}
-                                    multiline={true}
-                                    error={touched.note && Boolean(errors.note)}
-                                    helperText={touched.note && errors.note}
-                                    variant="outlined"
-                                    onChange={handleChangeComment}
-                                    fullWidth
-                                />
-                            </Grid>
-                            { notes.length > 0 && (
-                                <Grid xs={12} item>
-                                    <List className={classes.list}>
-                                        { renderNoteList() }
-                                    </List>
-                                </Grid>
-                            ) }
-                            <Grid xs={12} item>
-                                <Grid container spacing={2}>
-                                    <Grid xs={6} item>
-                                        <Button
-                                            onClick={() => {
-                                                setNewNote("");
-                                                setErrors({});
-                                            }}
-                                            color="primary"
-                                            variant="outlined"
-                                            fullWidth
-                                        >
-                                            Cancelar
-                                        </Button>
-                                    </Grid>
-                                    <Grid xs={6} item>
-                                        <ButtonWithSpinner loading={loading} color="primary" type="submit" variant="contained" autoFocus fullWidth>
-                                            Salvar
-                                        </ButtonWithSpinner>
-                                    </Grid>
-                                </Grid>
-                            </Grid>
-                        </Grid>
-                    </Form>
-                )}
-            </Formik>
-        </>
-    );
-}

+ 0 - 206
frontend/src/components/ContactNotesDialog/index.js

@@ -1,206 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import Button from '@material-ui/core/Button';
-import Dialog from '@material-ui/core/Dialog';
-import DialogActions from '@material-ui/core/DialogActions';
-import DialogContent from '@material-ui/core/DialogContent';
-import DialogTitle from '@material-ui/core/DialogTitle';
-import TextField from '@material-ui/core/TextField';
-import List from '@material-ui/core/List';
-import { makeStyles } from '@material-ui/core/styles';
-import * as Yup from "yup";
-import { Formik, Form, Field } from "formik";
-
-import ContactNotesDialogListItem from '../ContactNotesDialogListItem';
-import ConfirmationModal from '../ConfirmationModal';
-
-import { toast } from "react-toastify";
-
-import { i18n } from "../../translate/i18n";
-
-import ButtonWithSpinner from '../ButtonWithSpinner';
-
-import useTicketNotes from '../../hooks/useTicketNotes';
-
-const useStyles = makeStyles((theme) => ({
-    root: {
-        '& .MuiTextField-root': {
-            margin: theme.spacing(1),
-            width: '350px',
-        },
-    },
-    list: {
-        width: '100%',
-        maxWidth: '350px',
-        maxHeight: '200px',
-        backgroundColor: theme.palette.background.paper,
-    },
-    inline: {
-        width: '100%'
-    }
-}));
-
-const NoteSchema = Yup.object().shape({
-	note: Yup.string()
-		.min(2, "Too Short!")
-		.required("Required")
-});
-
-export default function ContactNotesDialog ({ modalOpen, onClose, ticket }) {
-    const { id: ticketId, contactId } = ticket
-    const classes = useStyles()
-    const [open, setOpen] = useState(false);
-    const [newNote, setNewNote] = useState({ note: "" });
-    const [loading, setLoading] = useState(false)
-    const [showOnDeleteDialog, setShowOnDeleteDialog] = useState(false)
-    const [selectedNote, setSelectedNote] = useState({})
-    const [notes, setNotes] = useState([])
-    const { saveNote, deleteNote, listNotes } = useTicketNotes()
-
-    useEffect(() => {
-        async function openAndFetchData () {
-            if (modalOpen) {
-                setOpen(true)
-                handleResetState()
-                await loadNotes()
-            }
-        }
-        openAndFetchData()
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [modalOpen])
-
-    const handleResetState = () => {
-        setNewNote({ note: "" })
-        setLoading(false)
-    }
-
-    const handleChangeComment = (e) => {
-        setNewNote({ note: e.target.value })
-    }
-    
-    const handleClose = () => {
-        setOpen(false);
-        onClose()
-    };
-
-    const handleSave = async values => {
-        setLoading(true)
-        try {
-            await saveNote({
-                ...values,
-                ticketId, 
-                contactId
-            })
-            await loadNotes()
-            setNewNote({ note: '' })
-            toast.success('Observação adicionada com sucesso!')
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const handleOpenDialogDelete = (item) => {
-        setSelectedNote(item)
-        setShowOnDeleteDialog(true)
-    }
-
-    const handleDelete = async () => {
-        setLoading(true)
-        try {
-            await deleteNote(selectedNote.id)
-            await loadNotes()
-            setSelectedNote({})
-            toast.success('Observação excluída com sucesso!')
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const loadNotes = async () => {
-        setLoading(true)
-        try {
-            const notes = await listNotes({ ticketId, contactId })
-            setNotes(notes)
-        } catch (e) {
-            toast.error(e)
-        }
-        setLoading(false)
-    }
-
-    const renderNoteList = () => {
-        return notes.map((note) => {
-            return <ContactNotesDialogListItem 
-                note={note} 
-                key={note.id}
-                deleteItem={handleOpenDialogDelete}
-            />
-        })
-    }
-
-    return (
-        <>
-            <ConfirmationModal
-                title="Excluir Registro"
-                open={showOnDeleteDialog}
-                onClose={setShowOnDeleteDialog}
-                onConfirm={handleDelete}
-            >
-                Deseja realmente excluir este registro?
-            </ConfirmationModal>
-            <Dialog
-                open={open}
-                onClose={handleClose}
-                aria-labelledby="alert-dialog-title"
-                aria-describedby="alert-dialog-description"
-            >
-                <DialogTitle id="alert-dialog-title">
-                    { i18n.t("ticketOptionsMenu.appointmentsModal.title") }
-                </DialogTitle>
-                <Formik
-                    initialValues={newNote}
-                    enableReinitialize={true}
-                    validationSchema={NoteSchema}
-                    onSubmit={(values, actions) => {
-                        setTimeout(() => {
-                            handleSave(values);
-                            actions.setSubmitting(false);
-                        }, 400);
-                    }}
-                >
-
-                    {({ touched, errors }) => (
-                        <Form>
-                            <DialogContent className={classes.root} dividers>
-                                <Field
-                                    as={TextField}
-                                    name="note"
-                                    rows={3}
-                                    label={i18n.t("ticketOptionsMenu.appointmentsModal.textarea")}
-                                    placeholder={i18n.t("ticketOptionsMenu.appointmentsModal.placeholder")}
-                                    multiline={true}
-                                    error={touched.note && Boolean(errors.note)}
-                                    helperText={touched.note && errors.note}
-                                    variant="outlined"
-                                    onChange={handleChangeComment}
-                                />
-
-                                <List className={classes.list}>
-                                    { renderNoteList() }
-                                </List>
-                            </DialogContent>
-                            <DialogActions>
-                                <Button onClick={handleClose} color="primary">
-                                    Fechar
-                                </Button>
-                                <ButtonWithSpinner loading={loading} color="primary" type="submit" variant="contained" autoFocus>
-                                    Salvar
-                                </ButtonWithSpinner>
-                            </DialogActions>
-                        </Form>
-                    )}
-                </Formik>
-            </Dialog>
-        </>
-    );
-}

+ 0 - 64
frontend/src/components/ContactNotesDialogListItem/index.js

@@ -1,64 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import IconButton from '@material-ui/core/IconButton';
-import ListItem from '@material-ui/core/ListItem';
-import ListItemText from '@material-ui/core/ListItemText';
-import ListItemAvatar from '@material-ui/core/ListItemAvatar';
-import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction';
-import Avatar from '@material-ui/core/Avatar';
-import Typography from '@material-ui/core/Typography';
-import { makeStyles } from '@material-ui/core/styles';
-import DeleteIcon from '@material-ui/icons/Delete';
-import moment from 'moment';
-
-const useStyles = makeStyles((theme) => ({
-    inline: {
-        width: '100%'
-    }
-}));
-
-export default function ContactNotesDialogListItem (props) {
-    const { note, deleteItem } = props;
-    const classes = useStyles();
-
-    const handleDelete = (item) => {
-        deleteItem(item);
-    }
-
-    return (
-        <ListItem alignItems="flex-start">
-            <ListItemAvatar>
-                <Avatar alt={note.user.name} src="/static/images/avatar/1.jpg" />
-            </ListItemAvatar>
-            <ListItemText
-                primary={
-                    <>
-                        <Typography
-                            component="span"
-                            variant="body2"
-                            className={classes.inline}
-                            color="textPrimary"
-                        >
-                            {note.note}
-                        </Typography>
-                    </>
-                }
-                secondary={
-                    <>
-                        {note.user.name}, {moment(note.createdAt).format('DD/MM/YY HH:mm')}
-                    </>
-                }
-            />
-            <ListItemSecondaryAction>
-                <IconButton onClick={() => handleDelete(note)} edge="end" aria-label="delete">
-                    <DeleteIcon />
-                </IconButton>
-            </ListItemSecondaryAction>
-        </ListItem>
-    )   
-}
-
-ContactNotesDialogListItem.propTypes = {
-    note: PropTypes.object.isRequired,
-    deleteItem: PropTypes.func.isRequired
-}

+ 0 - 26
frontend/src/components/ContactTag/index.js

@@ -1,26 +0,0 @@
-import { makeStyles } from "@material-ui/styles";
-import React from "react";
-
-const useStyles = makeStyles(theme => ({
-    tag: {
-        padding: "1px 5px",
-        borderRadius: "3px",
-        fontSize: "0.8em",
-        fontWeight: "bold",
-        color: "#FFF",
-        marginRight: "5px",
-        whiteSpace: "nowrap"
-    }
-}));
-
-const ContactTag = ({ tag }) => {
-    const classes = useStyles();
-
-    return (
-        <div className={classes.tag} style={{ backgroundColor: tag.color, marginTop: "2px" }}>
-            {tag.name.toUpperCase()}
-        </div>
-    )
-}
-
-export default ContactTag;

+ 0 - 50
frontend/src/components/CurrencyInput/index.js

@@ -1,50 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import MaskedInput from 'react-text-mask'
-import createNumberMask from 'text-mask-addons/dist/createNumberMask'
-
-const defaultMaskOptions = {
-  prefix: 'R$',
-  suffix: '',
-  includeThousandsSeparator: true,
-  thousandsSeparatorSymbol: '.',
-  allowDecimal: true,
-  decimalSymbol: ',',
-  decimalLimit: 2, // how many digits allowed after the decimal
-  integerLimit: 7, // limit length of integer numbers
-  allowNegative: false,
-  allowLeadingZeroes: false,
-}
-
-const CurrencyInput = ({ maskOptions, ...inputProps }) => {
-  const currencyMask = createNumberMask({
-    ...defaultMaskOptions,
-    ...maskOptions,
-  })
-
-  return <MaskedInput mask={currencyMask} {...inputProps} />
-}
-
-CurrencyInput.defaultProps = {
-  inputMode: 'numeric',
-  maskOptions: {},
-}
-
-CurrencyInput.propTypes = {
-  inputmode: PropTypes.string,
-  maskOptions: PropTypes.shape({
-    prefix: PropTypes.string,
-    suffix: PropTypes.string,
-    includeThousandsSeparator: PropTypes.bool,
-    thousandsSeparatorSymbol: PropTypes.string,
-    allowDecimal: PropTypes.bool,
-    decimalSymbol: PropTypes.string,
-    decimalLimit: PropTypes.string,
-    requireDecimal: PropTypes.bool,
-    allowNegative: PropTypes.bool,
-    allowLeadingZeroes: PropTypes.bool,
-    integerLimit: PropTypes.number,
-  }),
-}
-
-export default CurrencyInput

+ 0 - 70
frontend/src/components/DarkMode/index.js

@@ -1,70 +0,0 @@
-import React, { useState } from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { CssBaseline, IconButton } from "@material-ui/core";
-import Brightness4Icon from "@material-ui/icons/Brightness4";
-import Brightness7Icon from "@material-ui/icons/Brightness7";
-
-const useStyles = makeStyles((theme) => ({
-    icons: {
-        color: "#fff",
-    },
-    switch: {
-        color: "#fff",
-    },
-    visible: {
-        display: "none",
-    },
-    btnHeader: {
-        color: "#fff",
-    },
-}));
-
-const DarkMode = (props) => {
-    const classes = useStyles();
-
-    const [theme, setTheme] = useState("light");
-
-    const themeToggle = () => {
-        theme === "light" ? setTheme("dark") : setTheme("light");
-    };
-
-    const handleClick = () => {
-        props.themeToggle();
-        themeToggle();
-    };
-
-    return (
-        <>
-            {theme === "light" ? (
-                <>
-                    <CssBaseline />
-                    <IconButton
-                        className={classes.icons}
-                        onClick={handleClick}
-                        // ref={anchorEl}
-                        aria-label="Dark Mode"
-                        color="inherit"
-                    >
-                        <Brightness4Icon />
-                    </IconButton>
-                </>
-            ) : (
-                <>
-                    <CssBaseline />
-                    <IconButton
-                        className={classes.icons}
-                        onClick={handleClick}
-                        // ref={anchorEl}
-                        aria-label="Dark Mode"
-                        color="inherit"
-                    >
-                        <Brightness7Icon />
-                    </IconButton>
-                </>
-            )}
-        </>
-    );
-};
-
-export default DarkMode;

+ 0 - 53
frontend/src/components/Dashboard/CardCounter.js

@@ -1,53 +0,0 @@
-import React from "react";
-
-import { Avatar, Card, CardHeader, Typography } from "@material-ui/core";
-import Skeleton from "@material-ui/lab/Skeleton";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { grey } from '@material-ui/core/colors';
-
-const useStyles = makeStyles(theme => ({
-	cardAvatar: {
-		fontSize: '55px',
-		color: grey[500],
-		backgroundColor: '#ffffff',
-		width: theme.spacing(7),
-		height: theme.spacing(7)
-	},
-	cardTitle: {
-		fontSize: '18px',
-		color: theme.palette.text.primary
-	},
-	cardSubtitle: {
-		color: grey[600],
-		fontSize: '14px'
-	}
-}));
-
-export default function CardCounter(props) {
-    const { icon, title, value, loading } = props
-	const classes = useStyles();
-    return ( !loading ? 
-        <Card>
-            <CardHeader
-                avatar={
-                    <Avatar className={classes.cardAvatar}>
-                        {icon}
-                    </Avatar>
-                }
-                title={
-                    <Typography variant="h6" component="h2" className={classes.cardTitle}>
-                        { title }
-                    </Typography>
-                }
-                subheader={
-                    <Typography variant="subtitle1" component="p" className={classes.cardSubtitle}>
-                        { value }
-                    </Typography>
-                }
-            />
-        </Card>
-        : <Skeleton variant="rect" height={80} />
-    )
-    
-}

+ 0 - 89
frontend/src/components/Dashboard/TableAttendantsStatus.js

@@ -1,89 +0,0 @@
-import React from "react";
-
-import Paper from "@material-ui/core/Paper";
-import Table from '@material-ui/core/Table';
-import TableBody from '@material-ui/core/TableBody';
-import TableCell from '@material-ui/core/TableCell';
-import TableContainer from '@material-ui/core/TableContainer';
-import TableHead from '@material-ui/core/TableHead';
-import TableRow from '@material-ui/core/TableRow';
-import Skeleton from "@material-ui/lab/Skeleton";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green, red } from '@material-ui/core/colors';
-
-import CheckCircleIcon from '@material-ui/icons/CheckCircle';
-import ErrorIcon from '@material-ui/icons/Error';
-import moment from 'moment';
-
-import Rating from '@material-ui/lab/Rating';
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles(theme => ({
-	on: {
-		color: green[600],
-		fontSize: '20px'
-	},
-	off: {
-		color: red[600],
-		fontSize: '20px'
-	},
-    pointer: {
-        cursor: "pointer"
-    }
-}));
-
-export function RatingBox ({ rating }) {
-    const ratingTrunc = rating === null ? 0 : Math.trunc(rating);
-    return <Rating
-        defaultValue={ratingTrunc}
-        max={3}
-        readOnly
-    />
-}
-
-export default function TableAttendantsStatus(props) {
-    const { loading, attendants } = props
-	const classes = useStyles();
-
-    function renderList () {
-        return attendants.map((a, k) => (
-            <TableRow key={k}>
-                <TableCell>{a.name}</TableCell>
-                <TableCell align="center" title={i18n.t("dashboard.onlineTable.ratingLabel")} className={classes.pointer}>
-                    <RatingBox rating={a.rating} />
-                </TableCell>
-                <TableCell align="center">{formatTime(a.avgSupportTime, 2)}</TableCell>
-                <TableCell align="center">
-                    { a.online ?
-                        <CheckCircleIcon className={classes.on} />
-                        : <ErrorIcon className={classes.off} />
-                    }
-                </TableCell>
-            </TableRow>
-        ))
-    }
-
-	function formatTime(minutes){
-		return moment().startOf('day').add(minutes, 'minutes').format('HH[h] mm[m]');
-	}
-
-    return ( !loading ?
-        <TableContainer component={Paper}>
-            <Table>
-                <TableHead>
-                    <TableRow>
-                        <TableCell>{i18n.t("dashboard.onlineTable.name")}</TableCell>
-                        <TableCell align="center">{i18n.t("dashboard.onlineTable.ratings")}</TableCell>
-                        <TableCell align="center">{i18n.t("dashboard.onlineTable.avgSupportTime")}</TableCell>
-                        <TableCell align="center">{i18n.t("dashboard.onlineTable.status")}</TableCell>
-                    </TableRow>
-                </TableHead>
-                <TableBody>
-                    { renderList() }
-                </TableBody>
-            </Table>
-        </TableContainer>
-        : <Skeleton variant="rect" height={150} />
-    )
-}

+ 0 - 34
frontend/src/components/Dialog/index.js

@@ -1,34 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import CoreDialog from '@material-ui/core/Dialog';
-import DialogTitle from '@material-ui/core/DialogTitle';
-
-function Dialog ({ title, modalOpen, onClose, children }) {
-    const [open, setOpen] = useState(false);
-
-    useEffect(() => {
-        setOpen(modalOpen)
-    }, [modalOpen])
-    
-    const handleClose = () => {
-        setOpen(false);
-        onClose()
-    };
-
-    return (
-        <>
-            <CoreDialog
-                open={open}
-                onClose={handleClose}
-                aria-labelledby="alert-dialog-title"
-                aria-describedby="alert-dialog-description"
-            >
-                <DialogTitle id="alert-dialog-title">
-                    {title}
-                </DialogTitle>
-                {children}
-            </CoreDialog>
-        </>
-    );
-}
-
-export default Dialog;

+ 0 - 350
frontend/src/components/FileModal/index.js

@@ -1,350 +0,0 @@
-import React, { useState, useEffect, useContext } from "react";
-
-import * as Yup from "yup";
-import {
-    Formik,
-    Form,
-    Field,
-    FieldArray
-} from "formik";
-import { toast } from "react-toastify";
-
-import {
-    Box,
-    Button,
-    CircularProgress,
-    Dialog,
-    DialogActions,
-    DialogContent,
-    DialogTitle,
-    Divider,
-    Grid,
-    makeStyles,
-    TextField
-} from "@material-ui/core";
-import IconButton from "@material-ui/core/IconButton";
-import Typography from "@material-ui/core/Typography";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-
-import { green } from "@material-ui/core/colors";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { AuthContext } from "../../context/Auth/AuthContext";
-
-const useStyles = makeStyles(theme => ({
-    root: {
-        display: "flex",
-        flexWrap: "wrap",
-        gap: 4
-    },
-    multFieldLine: {
-        display: "flex",
-        "& > *:not(:last-child)": {
-            marginRight: theme.spacing(1),
-        },
-    },
-    textField: {
-        marginRight: theme.spacing(1),
-        flex: 1,
-    },
-
-    extraAttr: {
-        display: "flex",
-        justifyContent: "center",
-        alignItems: "center",
-    },
-
-    btnWrapper: {
-        position: "relative",
-    },
-
-    buttonProgress: {
-        color: green[500],
-        position: "absolute",
-        top: "50%",
-        left: "50%",
-        marginTop: -12,
-        marginLeft: -12,
-    },
-    formControl: {
-        margin: theme.spacing(1),
-        minWidth: 2000,
-    },
-    colorAdorment: {
-        width: 20,
-        height: 20,
-    },
-}));
-
-const FileListSchema = Yup.object().shape({
-    name: Yup.string()
-        .min(3, i18n.t("fileModal.formErrors.name.short"))
-        .required(i18n.t("fileModal.formErrors.name.required")),
-    message: Yup.string()
-        .required(i18n.t("fileModal.formErrors.message.required"))
-});
-
-const FilesModal = ({ open, onClose, fileListId, reload }) => {
-    const classes = useStyles();
-    const { user } = useContext(AuthContext);
-    const [ files, setFiles ] = useState([]);
-    const [selectedFileNames, setSelectedFileNames] = useState([]);
-
-
-    const initialState = {
-        name: "",
-        message: "",
-        options: [{ name: "", path:"", mediaType:"" }],
-    };
-
-    const [fileList, setFileList] = useState(initialState);
-
-    useEffect(() => {
-        try {
-            (async () => {
-                if (!fileListId) return;
-
-                const { data } = await api.get(`/files/${fileListId}`);
-                setFileList(data);
-            })()
-        } catch (err) {
-            toastError(err);
-        }
-    }, [fileListId, open]);
-
-    const handleClose = () => {
-        setFileList(initialState);
-        setFiles([]);
-        onClose();
-    };
-
-    const handleSaveFileList = async (values) => {
-
-        const uploadFiles = async (options, filesOptions, id) => {
-                const formData = new FormData();
-                formData.append("fileId", id);
-                formData.append("typeArch", "fileList")
-                filesOptions.forEach((fileOption, index) => {
-                    if (fileOption.file) {
-                        formData.append("files", fileOption.file);
-                        formData.append("mediaType", fileOption.file.type)
-                        formData.append("name", options[index].name);
-                        formData.append("id", options[index].id);
-                    }
-                });
-      
-              try {
-                const { data } = await api.post(`/files/uploadList/${id}`, formData);
-                setFiles([]);
-                return data;
-              } catch (err) {
-                toastError(err);
-              }
-            return null;
-        }
-
-        const fileData = { ...values, userId: user.id };
-        
-        try {
-            if (fileListId) {
-                const { data } = await api.put(`/files/${fileListId}`, fileData)
-                if (data.options.length > 0)
-
-                    uploadFiles(data.options, values.options, fileListId)
-            } else {
-                const { data } = await api.post("/files", fileData);
-                if (data.options.length > 0)
-                    uploadFiles(data.options, values.options, data.id)
-            }
-            toast.success(i18n.t("fileModal.success"));
-            if (typeof reload == 'function') {
-                reload();
-            }            
-        } catch (err) {
-            toastError(err);
-        }
-        handleClose();
-    };
-
-    return (
-        <div className={classes.root}>
-            <Dialog
-                open={open}
-                onClose={handleClose}
-                maxWidth="md"
-                fullWidth
-                scroll="paper">
-                <DialogTitle id="form-dialog-title">
-                    {(fileListId ? `${i18n.t("fileModal.title.edit")}` : `${i18n.t("fileModal.title.add")}`)}
-                </DialogTitle>
-                <Formik
-                    initialValues={fileList}
-                    enableReinitialize={true}
-                    validationSchema={FileListSchema}
-                    onSubmit={(values, actions) => {
-                        setTimeout(() => {
-                            handleSaveFileList(values);
-                            actions.setSubmitting(false);
-                        }, 400);
-                    }}
-                >
-                    {({ touched, errors, isSubmitting, values }) => (
-                        <Form>
-                            <DialogContent dividers>
-                                <div className={classes.multFieldLine}>
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("fileModal.form.name")}
-                                        name="name"
-                                        error={touched.name && Boolean(errors.name)}
-                                        helperText={touched.name && errors.name}
-                                        variant="outlined"
-                                        margin="dense"
-                                        fullWidth
-                                    />
-                                </div>
-                                <br />
-                                <div className={classes.multFieldLine}>
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("fileModal.form.message")}
-                                        type="message"
-                                        multiline
-                                        minRows={5}
-                                        fullWidth
-                                        name="message"
-                                        error={
-                                            touched.message && Boolean(errors.message)
-                                        }
-                                        helperText={
-                                            touched.message && errors.message
-                                        }
-                                        variant="outlined"
-                                        margin="dense"
-                                    />
-                                </div>
-                                <Typography
-                                    style={{ marginBottom: 8, marginTop: 12 }}
-                                    variant="subtitle1"
-                                >
-                                    {i18n.t("fileModal.form.fileOptions")}
-                                </Typography>
-
-                                <FieldArray name="options">
-                                    {({ push, remove }) => (
-                                        <>
-                                            {values.options &&
-                                                values.options.length > 0 &&
-                                                values.options.map((info, index) => (    
-                                                    <div
-                                                        className={classes.extraAttr}
-                                                        key={`${index}-info`}
-                                                    >
-                                                        <Grid container  spacing={0}>
-                                                            <Grid xs={6} md={10} item> 
-                                                                <Field
-                                                                    as={TextField}
-                                                                    label={i18n.t("fileModal.form.extraName")}
-                                                                    name={`options[${index}].name`}
-                                                                    variant="outlined"
-                                                                    margin="dense"
-                                                                    multiline
-                                                                    fullWidth
-                                                                    minRows={2}
-                                                                    className={classes.textField}
-                                                                />
-                                                            </Grid>     
-                                                            <Grid xs={2} md={2} item style={{ display: 'flex', alignItems: 'center', justifyContent: 'flex-end' }}>
-                                                                <input
-                                                                    type="file"
-                                                                    onChange={(e) => {
-                                                                        const selectedFile = e.target.files[0];
-                                                                        const updatedOptions = [...values.options];                                                                
-                                                                        updatedOptions[index].file = selectedFile;
-                                                                       
-                                                                        setFiles('options', updatedOptions);
-
-                                                                        // Atualize a lista selectedFileNames para o campo específico
-                                                                        const updatedFileNames = [...selectedFileNames];
-                                                                        updatedFileNames[index] = selectedFile ? selectedFile.name : '';
-                                                                        setSelectedFileNames(updatedFileNames);
-                                                                    }}
-                                                                    style={{ display: 'none' }}
-                                                                    name={`options[${index}].file`}
-                                                                    id={`file-upload-${index}`}
-                                                                />
-                                                                <label htmlFor={`file-upload-${index}`}>
-                                                                    <IconButton component="span">
-                                                                        <AttachFileIcon />
-                                                                    </IconButton>
-                                                                </label>
-                                                                <IconButton
-                                                                    size="small"
-                                                                    onClick={() => remove(index)}
-                                                                >
-                                                                    <DeleteOutlineIcon />
-                                                                </IconButton>    
-                                                            </Grid>
-                                                            <Grid xs={12} md={12} item>
-                                                                {info.path? info.path : selectedFileNames[index]}                               
-                                                            </Grid> 
-                                                        </Grid>                                                    
-                                                </div>                     
-                                                                                           
-                                                ))}
-                                            <div className={classes.extraAttr}>
-                                                <Button
-                                                    style={{ flex: 1, marginTop: 8 }}
-                                                    variant="outlined"
-                                                    color="primary"
-                                                    onClick={() => {push({ name: "", path: ""});
-                                                    setSelectedFileNames([...selectedFileNames, ""]);
-                                                }}
-                                                >
-                                                    {`+ ${i18n.t("fileModal.buttons.fileOptions")}`}
-                                                </Button>
-                                            </div>
-                                        </>
-                                    )}
-                                </FieldArray>
-                            </DialogContent>
-                            <DialogActions>
-                                <Button
-                                    onClick={handleClose}
-                                    color="secondary"
-                                    disabled={isSubmitting}
-                                    variant="outlined"
-                                >
-                                    {i18n.t("fileModal.buttons.cancel")}
-                                </Button>
-                                <Button
-                                    type="submit"
-                                    color="primary"
-                                    disabled={isSubmitting}
-                                    variant="contained"
-                                    className={classes.btnWrapper}
-                                >
-                                    {fileListId
-                                        ? `${i18n.t("fileModal.buttons.okEdit")}`
-                                        : `${i18n.t("fileModal.buttons.okAdd")}`}
-                                    {isSubmitting && (
-                                        <CircularProgress
-                                            size={24}
-                                            className={classes.buttonProgress}
-                                        />
-                                    )}
-                                </Button>
-                            </DialogActions>
-                        </Form>
-                    )}
-                </Formik>
-            </Dialog>
-        </div>
-    );
-};
-
-export default FilesModal;

+ 0 - 38
frontend/src/components/FormFields/CheckboxField.js

@@ -1,38 +0,0 @@
-import React from 'react';
-import { at } from 'lodash';
-import { useField } from 'formik';
-import {
-  Checkbox,
-  FormControl,
-  FormControlLabel,
-  FormHelperText
-} from '@material-ui/core';
-
-export default function CheckboxField(props) {
-  const { label, ...rest } = props;
-  const [field, meta, helper] = useField(props);
-  const { setValue } = helper;
-
-  function _renderHelperText() {
-    const [touched, error] = at(meta, 'touched', 'error');
-    if (touched && error) {
-      return <FormHelperText>{error}</FormHelperText>;
-    }
-  }
-
-  function _onChange(e) {
-    setValue(e.target.checked);
-  }
-
-  return (
-    <FormControl {...rest}>
-      <FormControlLabel
-        value={field.checked}
-        checked={field.checked}
-        control={<Checkbox {...field} onChange={_onChange} />}
-        label={label}
-      />
-      {_renderHelperText()}
-    </FormControl>
-  );
-}

+ 0 - 54
frontend/src/components/FormFields/DatePickerField.js

@@ -1,54 +0,0 @@
-import React, { useState, useEffect } from 'react';
-import { useField } from 'formik';
-import Grid from '@material-ui/core/Grid';
-import {
-  MuiPickersUtilsProvider,
-  KeyboardDatePicker
-} from '@material-ui/pickers';
-import DateFnsUtils from '@date-io/date-fns';
-
-export default function DatePickerField(props) {
-  const [field, meta, helper] = useField(props);
-  const { touched, error } = meta;
-  const { setValue } = helper;
-  const isError = touched && error && true;
-  const { value } = field;
-  const [selectedDate, setSelectedDate] = useState(null);
-
-  useEffect(() => {
-    if (value) {
-      const date = new Date(value);
-      setSelectedDate(date);
-    }
-  }, [value]);
-
-  function _onChange(date) {
-    if (date) {
-      setSelectedDate(date);
-      try {
-        const ISODateString = date.toISOString();
-        setValue(ISODateString);
-      } catch (error) {
-        setValue(date);
-      }
-    } else {
-      setValue(date);
-    }
-  }
-
-  return (
-    <Grid container>
-      <MuiPickersUtilsProvider utils={DateFnsUtils}>
-        <KeyboardDatePicker
-          {...field}
-          {...props}
-          value={selectedDate}
-          onChange={_onChange}
-          error={isError}
-          invalidDateMessage={isError && error}
-          helperText={isError && error}
-        />
-      </MuiPickersUtilsProvider>
-    </Grid>
-  );
-}

+ 0 - 26
frontend/src/components/FormFields/InputField.js

@@ -1,26 +0,0 @@
-import React from 'react';
-import { at } from 'lodash';
-import { useField } from 'formik';
-import { TextField } from '@material-ui/core';
-
-export default function InputField(props) {
-  const { errorText, ...rest } = props;
-  const [field, meta] = useField(props);
-
-  function _renderHelperText() {
-    const [touched, error] = at(meta, 'touched', 'error');
-    if (touched && error) {
-      return error;
-    }
-  }
-
-  return (
-    <TextField
-      type="text"
-      error={meta.touched && meta.error && true}
-      helperText={_renderHelperText()}
-      {...field}
-      {...rest}
-    />
-  );
-}

+ 0 - 48
frontend/src/components/FormFields/SelectField.js

@@ -1,48 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import { at } from 'lodash';
-import { useField } from 'formik';
-import {
-  InputLabel,
-  FormControl,
-  Select,
-  MenuItem,
-  FormHelperText
-} from '@material-ui/core';
-
-function SelectField(props) {
-  const { label, data, ...rest } = props;
-  const [field, meta] = useField(props);
-  const { value: selectedValue } = field;
-  const [touched, error] = at(meta, 'touched', 'error');
-  const isError = touched && error && true;
-  function _renderHelperText() {
-    if (isError) {
-      return <FormHelperText>{error}</FormHelperText>;
-    }
-  }
-
-  return (
-    <FormControl {...rest} error={isError}>
-      <InputLabel>{label}</InputLabel>
-      <Select {...field} value={selectedValue ? selectedValue : ''}>
-        {data.map((item, index) => (
-          <MenuItem key={index} value={item.value}>
-            {item.label}
-          </MenuItem>
-        ))}
-      </Select>
-      {_renderHelperText()}
-    </FormControl>
-  );
-}
-
-SelectField.defaultProps = {
-  data: []
-};
-
-SelectField.propTypes = {
-  data: PropTypes.array.isRequired
-};
-
-export default SelectField;

+ 0 - 5
frontend/src/components/FormFields/index.js

@@ -1,5 +0,0 @@
-import InputField from './InputField';
-import CheckboxField from './CheckboxField';
-import SelectField from './SelectField';
-import DatePickerField from './DatePickerField';
-export { InputField, CheckboxField, SelectField, DatePickerField };

+ 0 - 291
frontend/src/components/HelpsManager/index.js

@@ -1,291 +0,0 @@
-import React, { useState, useEffect } from "react";
-import {
-    makeStyles,
-    Paper,
-    Grid,
-    TextField,
-    Table,
-    TableHead,
-    TableBody,
-    TableCell,
-    TableRow,
-    IconButton
-} 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 useHelps from "../../hooks/useHelps";
-import { i18n } from "../../translate/i18n";
-
-
-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 HelpManagerForm (props) {
-    const { onSubmit, onDelete, onCancel, initialValue, loading } = props;
-    const classes = useStyles()
-
-    const [record, setRecord] = useState(initialValue);
-
-    useEffect(() => {
-        setRecord(initialValue)
-    }, [initialValue])
-
-    const handleSubmit = async(data) => {
-        onSubmit(data)
-    }
-
-    return (
-        <Formik
-            enableReinitialize
-            className={classes.fullWidth}
-            initialValues={record}
-            onSubmit={(values, { resetForm }) =>
-                setTimeout(() => {
-                    handleSubmit(values)
-                    resetForm()
-                }, 500)
-            }
-        >
-            {(values) => (
-                <Form className={classes.fullWidth}>
-                    <Grid spacing={2} justifyContent="flex-end" container>
-                        <Grid xs={12} sm={6} md={3} item>
-                            <Field
-                                as={TextField}
-                                label="Título"
-                                name="title"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                            />
-                        </Grid>
-                        <Grid xs={12} sm={6} md={3} item>
-                            <Field
-                                as={TextField}
-                                label="Código do Vídeo"
-                                name="video"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                            />
-                        </Grid>
-                        <Grid xs={12} sm={12} md={6} item>
-                            <Field
-                                as={TextField}
-                                label="Descrição"
-                                name="description"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                            />
-                        </Grid>
-                        <Grid sm={3} md={1} item>
-                            <ButtonWithSpinner className={classes.fullWidth} loading={loading} onClick={() => onCancel()} variant="contained">
-                                {i18n.t('settings.helps.buttons.clean')}
-                            </ButtonWithSpinner>
-                        </Grid>
-                        { record.id !== undefined ? (
-                            <Grid sm={3} md={1} item>
-                                <ButtonWithSpinner className={classes.fullWidth} loading={loading} onClick={() => onDelete(record)} variant="contained" color="secondary">
-                                    {i18n.t('settings.helps.buttons.delete')}
-                                </ButtonWithSpinner>
-                            </Grid>
-                        ) : null}
-                        <Grid sm={3} md={1} item>
-                            <ButtonWithSpinner className={classes.fullWidth} loading={loading} type="submit" variant="contained" color="primary">
-                                {i18n.t('settings.helps.buttons.save')}
-                            </ButtonWithSpinner>
-                        </Grid>
-                    </Grid>
-                </Form>
-            )}
-        </Formik>
-    )
-}
-
-export function HelpsManagerGrid (props) {
-    const { records, onSelect } = props
-    const classes = useStyles()
-
-    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">{i18n.t("settings.helps.grid.title")}</TableCell>
-                    <TableCell align="left">{i18n.t("settings.helps.grid.description")}</TableCell>
-                    <TableCell align="left">{i18n.t("settings.helps.grid.video")}</TableCell>
-                </TableRow>
-                </TableHead>
-                <TableBody>
-                {records.map((row) => (
-                    <TableRow key={row.id}>
-                        <TableCell align="center" style={{width: '1%'}}>
-                            <IconButton onClick={() => onSelect(row)} aria-label="delete">
-                                <EditIcon />
-                            </IconButton>
-                        </TableCell>
-                        <TableCell align="left">{row.title || '-'}</TableCell>
-                        <TableCell align="left">{row.description || '-'}</TableCell>
-                        <TableCell align="left">{row.video || '-'}</TableCell>
-                    </TableRow>
-                ))}
-                </TableBody>
-            </Table>
-        </Paper>
-    )
-}
-
-export default function HelpsManager () {
-    const classes = useStyles()
-    const { list, save, update, remove } = useHelps()
-    
-    const [showConfirmDialog, setShowConfirmDialog] = useState(false)
-    const [loading, setLoading] = useState(false)
-    const [records, setRecords] = useState([])
-    const [record, setRecord] = useState({
-        title: '',
-        description: '',
-        video: ''
-    })
-
-    useEffect(() => {
-        async function fetchData () {
-            await loadHelps()
-        }
-        fetchData()
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [])
-
-    const loadHelps = async () => {
-        setLoading(true)
-        try {
-            const helpList = await list()
-            setRecords(helpList)
-        } catch (e) {
-            toast.error(i18n.t('settings.helps.toasts.errorList'))
-        }
-        setLoading(false)
-    }
-
-    const handleSubmit = async (data) => {
-        setLoading(true)
-        try {
-            if (data.id !== undefined) {
-                await update(data)
-            } else {
-                await save(data)
-            }
-            await loadHelps()
-            handleCancel()
-            toast.success(i18n.t('settings.helps.toasts.success'))
-        } catch (e) {
-            toast.error(i18n.t('settings.helps.toasts.error'))
-        }
-        setLoading(false)
-    }
-
-    const handleDelete = async () => {
-        setLoading(true)
-        try {
-            await remove(record.id)
-            await loadHelps()
-            handleCancel()
-            toast.success(i18n.t('settings.helps.toasts.success'))
-        } catch (e) {
-            toast.error(i18n.t('settings.helps.toasts.errorOperation'))
-        }
-        setLoading(false)
-    }
-
-    const handleOpenDeleteDialog = () => {
-        setShowConfirmDialog(true)
-    }
-
-    const handleCancel = () => {
-        setRecord({
-            title: '',
-            description: '',
-            video: ''
-        })
-    }
-
-    const handleSelect = (data) => {
-        setRecord({
-            id: data.id,
-            title: data.title || '',
-            description: data.description || '',
-            video: data.video || ''
-        })
-    }
-
-    return (
-        <Paper className={classes.mainPaper} elevation={0}>
-            <Grid spacing={2} container>
-                <Grid xs={12} item>
-                    <HelpManagerForm 
-                        initialValue={record} 
-                        onDelete={handleOpenDeleteDialog} 
-                        onSubmit={handleSubmit} 
-                        onCancel={handleCancel} 
-                        loading={loading}
-                    />
-                </Grid>
-                <Grid xs={12} item>
-                    <HelpsManagerGrid 
-                        records={records}
-                        onSelect={handleSelect}
-                    />
-                </Grid>
-            </Grid>
-            <ConfirmationModal
-                title={i18n.t('settings.helps.confirmModal.title')}
-                open={showConfirmDialog}
-                onClose={() => setShowConfirmDialog(false)}
-                onConfirm={() => handleDelete()}
-            >
-                {i18n.t('settings.helps.confirmModal.confirm')}
-            </ConfirmationModal>
-        </Paper>
-    )
-}

+ 0 - 217
frontend/src/components/ImportContactsModal/index.js

@@ -1,217 +0,0 @@
-import { Button, Dialog, DialogActions, DialogContent, DialogTitle, Grid, IconButton, makeStyles, Modal, Typography } from "@material-ui/core";
-import { CloseOutlined, FontDownload, ImportContacts } from "@material-ui/icons";
-import React, { useState } from "react";
-import { FaDownload } from "react-icons/fa";
-import * as XLSX from 'xlsx';
-import { array } from "yup";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles((theme) => ({
-    root: {
-        display: "flex",
-        flexWrap: "wrap",
-    },
-    dialogImport: {
-        minWidth: 500,
-    },
-    iFile: {
-        display: "none"
-    },
-    lbFile: {
-        border: "dashed",
-        borderWidth: 2,
-        padding: 18,
-        cursor: "pointer",
-        display: "inline-block",
-        width: "70%"
-    },
-    btnWrapper: {
-        position: "relative"
-    },
-    iconPlanilha: {
-        marginRight: 10
-    },
-    cLbFile: {
-        textAlign: "center"
-    },
-    titleLb: {
-        textTransform: "uppercase",
-        fontWeight: "bolder",
-        marginTop:10
-    },
-    iconDownload: {
-        color: theme.palette.primary.main,
-        fontSize: 18
-    },
-    cModal: {
-        paddingTop: 50,
-        paddingBottom: 50
-    },
-    cSuccessContacts: {
-        backgroundColor: "#AAEE9C80",
-        padding: 10,
-        borderRadius: 8,
-        marginTop:30
-    },
-    cErrorContacts: {
-        backgroundColor: "#DD011B40",
-        padding: 10,
-        borderRadius: 8,
-        marginTop:30
-    },
-    titleResult: {
-        fontWeight: "bolder"
-    },
-    cCloseModal: {
-        textAlign: "end"
-    }
-}))
-
-const ImportContactsModal = ( props ) => {
-
-    const classes = useStyles();
-
-    const {
-        open,
-        onClose
-    } = props;
-    const [isSubmitting, setIsSubmitting] = useState(false);
-    const [nameFile, setNameFile] = useState('');
-    const [listcontacts, setListContacts] = useState([]);
-    const [successUpload, setSuccessUpload] = useState([]);
-    const [errorUpload, setErrorUpload] = useState([]);
-
-    const handleNewFile = ( e ) => {
-
-        const file = e.target.files[0];
-
-        if(!file) return;
-
-        setNameFile( file.name );
-        readXlsx( file );
-    }
-
-    const readXlsx = ( file ) => {
-
-        const reader = new FileReader();
-        reader.onload = ( e ) => {
-
-            const ab = e.target.result;
-            const wb = XLSX.read(ab,{type: 'array'})
-
-            const wsname = wb.SheetNames[0];
-            const ws = wb.Sheets[wsname];
-
-            const data = XLSX.utils.sheet_to_json(ws);
-            setListContacts(data);
-        }
-
-        reader.readAsArrayBuffer(file);
-    }
-
-    const handleSaveListContacts = async (  ) => {
-
-        setIsSubmitting(true);
-        try{
-
-            const {data: responseData} = await api.post("/contacts/upload", listcontacts);
-            setSuccessUpload(responseData.newContacts);
-            setErrorUpload(responseData.errorBag);
-
-        }catch(e){
-            toastError(e);
-        }finally{
-            setIsSubmitting(false);
-        }
-    }
-
-    const handleDownloadModel = (  ) => {
-        
-        window.location.href = `${window.location.protocol}//${window.location.host}/import-contatos.xlsx`;
-    }
-
-    return (
-        <div >
-            <Dialog open={open} maxWidth="sm" fullWidth scroll="paper" >
-                <DialogTitle>
-                    <Grid container alignItems="center">
-                        <Grid item xs={6}>
-                            {i18n.t("contactImportModal.title")}
-                        </Grid>
-                        <Grid item xs={6} className={classes.cCloseModal}>
-                            <IconButton onClick={onClose}>
-                                <CloseOutlined />  
-                            </IconButton>                                                                          
-                        </Grid>
-                    </Grid>
-                </DialogTitle>
-                <DialogContent dividers className={classes.cModal}>
-                    <div className={classes.cLbFile}>
-                        <label className={classes.lbFile} htmlFor="i-import-contacts">
-                            <FaDownload className={classes.iconDownload} />
-                            <div className={classes.titleLb}>
-                                {i18n.t("contactImportModal.labels.import")}
-                            </div>
-                            {nameFile !== '' && (
-                                <div>
-                                    ({ nameFile } - {listcontacts.length} {i18n.t("contactImportModal.labels.result")})
-                                </div> 
-                            )}                                                      
-                        </label>
-                        <input onChange={handleNewFile} className={classes.iFile} type="file" accept=".xlsx" id="i-import-contacts"/>
-                    </div>
-                    {successUpload.length > 0 && (
-                        <div className={classes.cSuccessContacts}>
-                            <Typography className={classes.titleResult}>
-                                {i18n.t("contactImportModal.labels.added")}:
-                            </Typography>
-                            {successUpload.map((contact) => (
-                                <div>
-                                    {contact.contactId} | {contact.contactName} - {i18n.t("contactImportModal.labels.savedContact")}
-                                </div>
-                            ))}
-                        </div>
-                    )}                    
-                    {errorUpload.length > 0 && (
-                        <div className={classes.cErrorContacts}>
-                            <Typography className={classes.titleResult}>
-                                {i18n.t("contactImportModal.labels.errors")}:
-                            </Typography>
-                            <ul>
-                                {errorUpload.map((contact) => (
-                                    <li>
-                                        {contact.contactName} - {contact.error.message} 
-                                    </li>
-                                ))}
-                            </ul>
-                        </div>
-                    )}                    
-                </DialogContent>
-                <DialogActions>
-                    <Button
-                        color="primary"
-                        disabled={isSubmitting}
-                        variant="outlined"
-                        onClick={handleDownloadModel}
-                    >
-                        <ImportContacts className={classes.iconPlanilha} />
-                        {i18n.t("contactImportModal.buttons.download")}
-                    </Button>
-                    <Button
-                        color="primary"
-                        disabled={isSubmitting}
-                        variant="contained"
-                        className={classes.btnWrapper}
-                        onClick={handleSaveListContacts}
-                    >
-                        {i18n.t("contactImportModal.buttons.import")}
-                    </Button>
-                </DialogActions>
-            </Dialog>
-        </div>
-    );
-}
-
-export default ImportContactsModal;

+ 0 - 45
frontend/src/components/LanguageControl/index.js

@@ -1,45 +0,0 @@
-import React, { useEffect, useState } from 'react';
-import { changeLanguage, i18n } from "../../translate/i18n";
-import { RadioGroup, FormControlLabel, Radio } from '@material-ui/core';
-import api from "../../services/api";
-
-const LanguageControl = () => {
-    const [selectedLanguage, setSelectedLanguage] = useState('en');
-
-    const handleLanguageChange = async (event) => {
-        const newLanguage = event.target.value;
-        setSelectedLanguage(newLanguage);
-        changeLanguage(newLanguage);
-
-        try{
-            await api.post(`/users/set-language/${newLanguage}`);
-        }catch(error){
-            console.error(error);
-        }
-
-    };
-
-    useEffect(() => {
-        const saveLanguage = localStorage.getItem('i18nextLng');
-        setSelectedLanguage(saveLanguage);
-    }, []);
-
-    return (
-        <div>
-            <label htmlFor="language-select">{i18n.t("selectLanguage")}</label>
-            <RadioGroup
-                aria-label="language"
-                name="language-radio-group"
-                value={selectedLanguage}
-                onChange={handleLanguageChange}
-                row
-            >
-                <FormControlLabel value="pt" control={<Radio />} label="Português (BR)" />
-                <FormControlLabel value="en" control={<Radio />} label="English" />
-                <FormControlLabel value="es" control={<Radio />} label="Español" />
-            </RadioGroup>
-        </div>
-    );
-};
-
-export default LanguageControl;

+ 0 - 53
frontend/src/components/LocationPreview/index.js

@@ -1,53 +0,0 @@
-import React, { useEffect } from 'react';
-import toastError from "../../errors/toastError";
-
-import { Button, Divider, Typography} from "@material-ui/core";
-import { i18n } from '../../translate/i18n';
-
-const LocationPreview = ({ image, link, description }) => {
-    useEffect(() => {}, [image, link, description]);
-
-    const handleLocation = async() => {
-        try {
-            window.open(link);
-        } catch (err) {
-            toastError(err);
-        }
-    }
-
-    return (
-		<>
-			<div style={{
-				minWidth: "250px",
-			}}>
-				<div>
-					<div style={{ float: "left" }}>
-						<img src={image} alt="loc" onClick={handleLocation} style={{ width: "100px" }} />
-					</div>
-					{ description && (
-					<div style={{ display: "flex", flexWrap: "wrap" }}>
-						<Typography style={{ marginTop: "12px", marginLeft: "15px", marginRight: "15px", float: "left" }} variant="subtitle1" color="primary" gutterBottom>
-							<div dangerouslySetInnerHTML={{ __html: description.replace('\\n', '<br />') }}></div>
-						</Typography>
-					</div>
-					)}
-					<div style={{ display: "block", content: "", clear: "both" }}></div>
-					<div>
-						<Divider />
-						<Button
-							fullWidth
-							color="primary"
-							onClick={handleLocation}
-							disabled={!link}
-						>
-							{i18n.t("locationPreview.button")}
-						</Button>
-					</div>
-				</div>
-			</div>
-		</>
-	);
-
-};
-
-export default LocationPreview;

+ 0 - 31
frontend/src/components/MainContainer/index.js

@@ -1,31 +0,0 @@
-import React from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-import Container from "@material-ui/core/Container";
-
-const useStyles = makeStyles(theme => ({
-	mainContainer: {
-		flex: 1,
-		padding: theme.spacing(2),
-		height: `calc(100% - 48px)`,
-	},
-
-	contentWrapper: {
-		height: "100%",
-		overflowY: "hidden",
-		display: "flex",
-		flexDirection: "column",
-	},
-}));
-
-const MainContainer = ({ children }) => {
-	const classes = useStyles();
-
-	return (
-		<Container className={classes.mainContainer}>
-			<div className={classes.contentWrapper}>{children}</div>
-		</Container>
-	);
-};
-
-export default MainContainer;

+ 0 - 19
frontend/src/components/MainHeader/index.js

@@ -1,19 +0,0 @@
-import React from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-
-const useStyles = makeStyles(theme => ({
-	contactsHeader: {
-		display: "flex",
-		alignItems: "center",
-		padding: "0px 6px 6px 6px",
-	},
-}));
-
-const MainHeader = ({ children }) => {
-	const classes = useStyles();
-
-	return <div className={classes.contactsHeader}>{children}</div>;
-};
-
-export default MainHeader;

+ 0 - 21
frontend/src/components/MainHeaderButtonsWrapper/index.js

@@ -1,21 +0,0 @@
-import React from "react";
-
-import { makeStyles } from "@material-ui/core/styles";
-
-const useStyles = makeStyles(theme => ({
-	MainHeaderButtonsWrapper: {
-		flex: "none",
-		marginLeft: "auto",
-		"& > *": {
-			margin: theme.spacing(1),
-		},
-	},
-}));
-
-const MainHeaderButtonsWrapper = ({ children }) => {
-	const classes = useStyles();
-
-	return <div className={classes.MainHeaderButtonsWrapper}>{children}</div>;
-};
-
-export default MainHeaderButtonsWrapper;

+ 0 - 186
frontend/src/components/MarkdownWrapper/index.js

@@ -1,186 +0,0 @@
-import React from "react";
-import Markdown from "markdown-to-jsx";
-
-const elements = [
-	"a",
-	"abbr",
-	"address",
-	"area",
-	"article",
-	"aside",
-	"audio",
-	"b",
-	"base",
-	"bdi",
-	"bdo",
-	"big",
-	"blockquote",
-	"body",
-	"br",
-	"button",
-	"canvas",
-	"caption",
-	"cite",
-	"code",
-	"col",
-	"colgroup",
-	"data",
-	"datalist",
-	"dd",
-	"del",
-	"details",
-	"dfn",
-	"dialog",
-	"div",
-	"dl",
-	"dt",
-	"em",
-	"embed",
-	"fieldset",
-	"figcaption",
-	"figure",
-	"footer",
-	"form",
-	"h1",
-	"h2",
-	"h3",
-	"h4",
-	"h5",
-	"h6",
-	"head",
-	"header",
-	"hgroup",
-	"hr",
-	"html",
-	"i",
-	"iframe",
-	"img",
-	"input",
-	"ins",
-	"kbd",
-	"keygen",
-	"label",
-	"legend",
-	"li",
-	"link",
-	"main",
-	"map",
-	"mark",
-	"marquee",
-	"menu",
-	"menuitem",
-	"meta",
-	"meter",
-	"nav",
-	"noscript",
-	"object",
-	"ol",
-	"optgroup",
-	"option",
-	"output",
-	"p",
-	"param",
-	"picture",
-	"pre",
-	"progress",
-	"q",
-	"rp",
-	"rt",
-	"ruby",
-	"s",
-	"samp",
-	"script",
-	"section",
-	"select",
-	"small",
-	"source",
-	"span",
-	"strong",
-	"style",
-	"sub",
-	"summary",
-	"sup",
-	"table",
-	"tbody",
-	"td",
-	"textarea",
-	"tfoot",
-	"th",
-	"thead",
-	"time",
-	"title",
-	"tr",
-	"track",
-	"u",
-	"ul",
-	"var",
-	"video",
-	"wbr",
-
-	// SVG
-	"circle",
-	"clipPath",
-	"defs",
-	"ellipse",
-	"foreignObject",
-	"g",
-	"image",
-	"line",
-	"linearGradient",
-	"marker",
-	"mask",
-	"path",
-	"pattern",
-	"polygon",
-	"polyline",
-	"radialGradient",
-	"rect",
-	"stop",
-	"svg",
-	"text",
-	"tspan",
-];
-
-const allowedElements = ["a", "b", "strong", "em", "u", "code", "del"];
-
-const CustomLink = ({ children, ...props }) => (
-	<a {...props} target="_blank" rel="noopener noreferrer">
-		{children}
-	</a>
-);
-
-const MarkdownWrapper = ({ children }) => {
-	const boldRegex = /\*(.*?)\*/g;
-	const tildaRegex = /~(.*?)~/g;
-
-	if (children && boldRegex.test(children)) {
-		children = children.replace(boldRegex, "**$1**");
-	}
-	if (children && tildaRegex.test(children)) {
-		children = children.replace(tildaRegex, "~~$1~~");
-	}
-
-	const options = React.useMemo(() => {
-		const markdownOptions = {
-			disableParsingRawHTML: true,
-			forceInline: true,
-			overrides: {
-				a: { component: CustomLink },
-			},
-		};
-
-		elements.forEach(element => {
-			if (!allowedElements.includes(element)) {
-				markdownOptions.overrides[element] = el => el.children || null;
-			}
-		});
-
-		return markdownOptions;
-	}, []);
-
-	if (!children) return null;
-
-	return <Markdown options={options}>{children}</Markdown>;
-};
-
-export default MarkdownWrapper;

+ 0 - 48
frontend/src/components/MessageInput/RecordingTimer.js

@@ -1,48 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-
-const useStyles = makeStyles(theme => ({
-	timerBox: {
-		display: "flex",
-		marginLeft: 10,
-		marginRight: 10,
-		alignItems: "center",
-	},
-}));
-
-const RecordingTimer = () => {
-	const classes = useStyles();
-	const initialState = {
-		minutes: 0,
-		seconds: 0,
-	};
-	const [timer, setTimer] = useState(initialState);
-
-	useEffect(() => {
-		const interval = setInterval(
-			() =>
-				setTimer(prevState => {
-					if (prevState.seconds === 59) {
-						return { ...prevState, minutes: prevState.minutes + 1, seconds: 0 };
-					}
-					return { ...prevState, seconds: prevState.seconds + 1 };
-				}),
-			1000
-		);
-		return () => {
-			clearInterval(interval);
-		};
-	}, []);
-
-	const addZero = n => {
-		return n < 10 ? "0" + n : n;
-	};
-
-	return (
-		<div className={classes.timerBox}>
-			<span>{`${addZero(timer.minutes)}:${addZero(timer.seconds)}`}</span>
-		</div>
-	);
-};
-
-export default RecordingTimer;

+ 0 - 513
frontend/src/components/MessageInput/index.js

@@ -1,513 +0,0 @@
-import React, { useState, useEffect, useContext, useRef } from "react";
-import "emoji-mart/css/emoji-mart.css";
-import { useParams } from "react-router-dom";
-import { Picker } from "emoji-mart";
-import MicRecorder from "mic-recorder-to-mp3";
-import clsx from "clsx";
-
-import { makeStyles } from "@material-ui/core/styles";
-import Paper from "@material-ui/core/Paper";
-import InputBase from "@material-ui/core/InputBase";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import { green } from "@material-ui/core/colors";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-import IconButton from "@material-ui/core/IconButton";
-import MoodIcon from "@material-ui/icons/Mood";
-import SendIcon from "@material-ui/icons/Send";
-import CancelIcon from "@material-ui/icons/Cancel";
-import ClearIcon from "@material-ui/icons/Clear";
-import MicIcon from "@material-ui/icons/Mic";
-import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
-import HighlightOffIcon from "@material-ui/icons/HighlightOff";
-import { FormControlLabel, Switch } from "@material-ui/core";
-
-import { i18n } from "../../translate/i18n";
-import api from "../../services/api";
-import RecordingTimer from "./RecordingTimer";
-import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { useLocalStorage } from "../../hooks/useLocalStorage";
-import toastError from "../../errors/toastError";
-
-const Mp3Recorder = new MicRecorder({ bitRate: 128 });
-
-const useStyles = makeStyles(theme => ({
-	mainWrapper: {
-		backgroundColor: theme.palette.bordabox, //DARK MODE PLW DESIGN//
-		display: "flex",
-		flexDirection: "column",
-		alignItems: "center",
-		borderTop: "1px solid rgba(0, 0, 0, 0.12)",
-	},
-
-	newMessageBox: {
-		background: "#eee",
-		width: "100%",
-		display: "flex",
-		padding: "7px",
-		alignItems: "center",
-	},
-
-	messageInputWrapper: {
-		padding: 6,
-		marginRight: 7,
-		background: "#fff",
-		display: "flex",
-		borderRadius: 20,
-		flex: 1,
-	},
-
-	messageInput: {
-		paddingLeft: 10,
-		flex: 1,
-		border: "none",
-	},
-
-	sendMessageIcons: {
-		color: "grey",
-	},
-
-	uploadInput: {
-		display: "none",
-	},
-
-	viewMediaInputWrapper: {
-		display: "flex",
-		padding: "10px 13px",
-		position: "relative",
-		justifyContent: "space-between",
-		alignItems: "center",
-		backgroundColor: "#eee",
-		borderTop: "1px solid rgba(0, 0, 0, 0.12)",
-	},
-
-	emojiBox: {
-		position: "absolute",
-		bottom: 63,
-		width: 40,
-		borderTop: "1px solid #e8e8e8",
-	},
-
-	circleLoading: {
-		color: green[500],
-		opacity: "70%",
-		position: "absolute",
-		top: "20%",
-		left: "50%",
-		marginLeft: -12,
-	},
-
-	audioLoading: {
-		color: green[500],
-		opacity: "70%",
-	},
-
-	recorderWrapper: {
-		display: "flex",
-		alignItems: "center",
-		alignContent: "middle",
-	},
-
-	cancelAudioIcon: {
-		color: "red",
-	},
-
-	sendAudioIcon: {
-		color: "green",
-	},
-
-	replyginMsgWrapper: {
-		display: "flex",
-		width: "100%",
-		alignItems: "center",
-		justifyContent: "center",
-		paddingTop: 8,
-		paddingLeft: 73,
-		paddingRight: 7,
-	},
-
-	replyginMsgContainer: {
-		flex: 1,
-		marginRight: 5,
-		overflowY: "hidden",
-		backgroundColor: "rgba(0, 0, 0, 0.05)",
-		borderRadius: "7.5px",
-		display: "flex",
-		position: "relative",
-	},
-
-	replyginMsgBody: {
-		padding: 10,
-		height: "auto",
-		display: "block",
-		whiteSpace: "pre-wrap",
-		overflow: "hidden",
-	},
-
-	replyginContactMsgSideColor: {
-		flex: "none",
-		width: "4px",
-		backgroundColor: "#35cd96",
-	},
-
-	replyginSelfMsgSideColor: {
-		flex: "none",
-		width: "4px",
-		backgroundColor: "#6bcbef",
-	},
-
-	messageContactName: {
-		display: "flex",
-		color: "#6bcbef",
-		fontWeight: 500,
-	},
-}));
-
-const MessageInput = ({ ticketStatus }) => {
-	const classes = useStyles();
-	const { ticketId } = useParams();
-
-	const [medias, setMedias] = useState([]);
-	const [inputMessage, setInputMessage] = useState("");
-	const [showEmoji, setShowEmoji] = useState(false);
-	const [loading, setLoading] = useState(false);
-	const [recording, setRecording] = useState(false);
-	const inputRef = useRef();
-	const { setReplyingMessage, replyingMessage } = useContext(
-		ReplyMessageContext
-	);
-	const { user } = useContext(AuthContext);
-
-	const [signMessage, setSignMessage] = useLocalStorage("signOption", true);
-
-	useEffect(() => {
-		inputRef.current.focus();
-	}, [replyingMessage]);
-
-	useEffect(() => {
-		inputRef.current.focus();
-		return () => {
-			setInputMessage("");
-			setShowEmoji(false);
-			setMedias([]);
-			setReplyingMessage(null);
-		};
-	}, [ticketId, setReplyingMessage]);
-
-	const handleChangeInput = e => {
-		setInputMessage(e.target.value);
-	};
-
-	const handleAddEmoji = e => {
-		let emoji = e.native;
-		setInputMessage(prevState => prevState + emoji);
-	};
-
-	const handleChangeMedias = e => {
-		if (!e.target.files) {
-			return;
-		}
-
-		const selectedMedias = Array.from(e.target.files);
-		setMedias(selectedMedias);
-	};
-
-	const handleInputPaste = e => {
-		if (e.clipboardData.files[0]) {
-			setMedias([e.clipboardData.files[0]]);
-		}
-	};
-
-	const handleUploadMedia = async e => {
-		setLoading(true);
-		e.preventDefault();
-
-		const formData = new FormData();
-		formData.append("fromMe", true);
-		medias.forEach(media => {
-			formData.append("medias", media);
-			formData.append("body", media.name);
-		});
-
-		try {
-			await api.post(`/messages/${ticketId}`, formData);
-		} catch (err) {
-			toastError(err);
-		}
-
-		setLoading(false);
-		setMedias([]);
-	};
-
-	const handleSendMessage = async () => {
-		if (inputMessage.trim() === "") return;
-		setLoading(true);
-
-		const message = {
-			read: 1,
-			fromMe: true,
-			mediaUrl: "",
-			body: signMessage
-				? `*${user?.name}:*\n${inputMessage.trim()}`
-				: inputMessage.trim(),
-			quotedMsg: replyingMessage,
-		};
-		try {
-			await api.post(`/messages/${ticketId}`, message);
-		} catch (err) {
-			toastError(err);
-		}
-
-		setInputMessage("");
-		setShowEmoji(false);
-		setLoading(false);
-		setReplyingMessage(null);
-	};
-
-	const handleStartRecording = async () => {
-		setLoading(true);
-		try {
-			await navigator.mediaDevices.getUserMedia({ audio: true });
-			await Mp3Recorder.start();
-			setRecording(true);
-			setLoading(false);
-		} catch (err) {
-			toastError(err);
-			setLoading(false);
-		}
-	};
-
-	const handleUploadAudio = async () => {
-		setLoading(true);
-		try {
-			const [, blob] = await Mp3Recorder.stop().getMp3();
-			if (blob.size < 10000) {
-				setLoading(false);
-				setRecording(false);
-				return;
-			}
-
-			const formData = new FormData();
-			const filename = `${new Date().getTime()}.mp3`;
-			formData.append("medias", blob, filename);
-			formData.append("body", filename);
-			formData.append("fromMe", true);
-
-			await api.post(`/messages/${ticketId}`, formData);
-		} catch (err) {
-			toastError(err);
-		}
-
-		setRecording(false);
-		setLoading(false);
-	};
-
-	const handleCancelAudio = async () => {
-		try {
-			await Mp3Recorder.stop().getMp3();
-			setRecording(false);
-		} catch (err) {
-			toastError(err);
-		}
-	};
-
-	const renderReplyingMessage = message => {
-		return (
-			<div className={classes.replyginMsgWrapper}>
-				<div className={classes.replyginMsgContainer}>
-					<span
-						className={clsx(classes.replyginContactMsgSideColor, {
-							[classes.replyginSelfMsgSideColor]: !message.fromMe,
-						})}
-					></span>
-					<div className={classes.replyginMsgBody}>
-						{!message.fromMe && (
-							<span className={classes.messageContactName}>
-								{message.contact?.name}
-							</span>
-						)}
-						{message.body}
-					</div>
-				</div>
-				<IconButton
-					aria-label="showRecorder"
-					component="span"
-					disabled={loading || ticketStatus !== "open"}
-					onClick={() => setReplyingMessage(null)}
-				>
-					<ClearIcon className={classes.sendMessageIcons} />
-				</IconButton>
-			</div>
-		);
-	};
-
-	if (medias.length > 0)
-		return (
-			<Paper elevation={0} square className={classes.viewMediaInputWrapper}>
-				<IconButton
-					aria-label="cancel-upload"
-					component="span"
-					onClick={e => setMedias([])}
-				>
-					<CancelIcon className={classes.sendMessageIcons} />
-				</IconButton>
-
-				{loading ? (
-					<div>
-						<CircularProgress className={classes.circleLoading} />
-					</div>
-				) : (
-					<span>
-						{medias[0]?.name}
-						{/* <img src={media.preview} alt=""></img> */}
-					</span>
-				)}
-				<IconButton
-					aria-label="send-upload"
-					component="span"
-					onClick={handleUploadMedia}
-					disabled={loading}
-				>
-					<SendIcon className={classes.sendMessageIcons} />
-				</IconButton>
-			</Paper>
-		);
-	else {
-		return (
-			<Paper square elevation={0} className={classes.mainWrapper}>
-				{replyingMessage && renderReplyingMessage(replyingMessage)}
-				<div className={classes.newMessageBox}>
-					<IconButton
-						aria-label="emojiPicker"
-						component="span"
-						disabled={loading || recording || ticketStatus !== "open"}
-						onClick={e => setShowEmoji(prevState => !prevState)}
-					>
-						<MoodIcon className={classes.sendMessageIcons} />
-					</IconButton>
-					{showEmoji ? (
-						<div className={classes.emojiBox}>
-							<Picker
-								perLine={16}
-								showPreview={false}
-								showSkinTones={false}
-								onSelect={handleAddEmoji}
-							/>
-						</div>
-					) : null}
-
-					<input
-						multiple
-						type="file"
-						id="upload-button"
-						disabled={loading || recording || ticketStatus !== "open"}
-						className={classes.uploadInput}
-						onChange={handleChangeMedias}
-					/>
-					<label htmlFor="upload-button">
-						<IconButton
-							aria-label="upload"
-							component="span"
-							disabled={loading || recording || ticketStatus !== "open"}
-						>
-							<AttachFileIcon className={classes.sendMessageIcons} />
-						</IconButton>
-					</label>
-					<FormControlLabel
-						style={{ marginRight: 7, color: "gray" }}
-						label={i18n.t("messagesInput.signMessage")}
-						labelPlacement="start"
-						control={
-							<Switch
-								size="small"
-								checked={signMessage}
-								onChange={e => {
-									setSignMessage(e.target.checked);
-								}}
-								name="showAllTickets"
-								color="primary"
-							/>
-						}
-					/>
-					<div className={classes.messageInputWrapper}>
-						<InputBase
-							inputRef={input => {
-								input && input.focus();
-								input && (inputRef.current = input);
-							}}
-							className={classes.messageInput}
-							placeholder={
-								ticketStatus === "open"
-									? i18n.t("messagesInput.placeholderOpen")
-									: i18n.t("messagesInput.placeholderClosed")
-							}
-							multiline
-							maxRows={5}
-							value={inputMessage}
-							onChange={handleChangeInput}
-							disabled={recording || loading || ticketStatus !== "open"}
-							onPaste={e => {
-								ticketStatus === "open" && handleInputPaste(e);
-							}}
-							onKeyPress={e => {
-								if (loading || e.shiftKey) return;
-								else if (e.key === "Enter") {
-									handleSendMessage();
-								}
-							}}
-						/>
-					</div>
-					{inputMessage ? (
-						<IconButton
-							aria-label="sendMessage"
-							component="span"
-							onClick={handleSendMessage}
-							disabled={loading}
-						>
-							<SendIcon className={classes.sendMessageIcons} />
-						</IconButton>
-					) : recording ? (
-						<div className={classes.recorderWrapper}>
-							<IconButton
-								aria-label="cancelRecording"
-								component="span"
-								fontSize="large"
-								disabled={loading}
-								onClick={handleCancelAudio}
-							>
-								<HighlightOffIcon className={classes.cancelAudioIcon} />
-							</IconButton>
-							{loading ? (
-								<div>
-									<CircularProgress className={classes.audioLoading} />
-								</div>
-							) : (
-								<RecordingTimer />
-							)}
-
-							<IconButton
-								aria-label="sendRecordedAudio"
-								component="span"
-								onClick={handleUploadAudio}
-								disabled={loading}
-							>
-								<CheckCircleOutlineIcon className={classes.sendAudioIcon} />
-							</IconButton>
-						</div>
-					) : (
-						<IconButton
-							aria-label="showRecorder"
-							component="span"
-							disabled={loading || ticketStatus !== "open"}
-							onClick={handleStartRecording}
-						>
-							<MicIcon className={classes.sendMessageIcons} />
-						</IconButton>
-					)}
-				</div>
-			</Paper>
-		);
-	}
-};
-
-export default MessageInput;

+ 0 - 48
frontend/src/components/MessageInputCustom/RecordingTimer.js

@@ -1,48 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-
-const useStyles = makeStyles(theme => ({
-	timerBox: {
-		display: "flex",
-		marginLeft: 10,
-		marginRight: 10,
-		alignItems: "center",
-	},
-}));
-
-const RecordingTimer = () => {
-	const classes = useStyles();
-	const initialState = {
-		minutes: 0,
-		seconds: 0,
-	};
-	const [timer, setTimer] = useState(initialState);
-
-	useEffect(() => {
-		const interval = setInterval(
-			() =>
-				setTimer(prevState => {
-					if (prevState.seconds === 59) {
-						return { ...prevState, minutes: prevState.minutes + 1, seconds: 0 };
-					}
-					return { ...prevState, seconds: prevState.seconds + 1 };
-				}),
-			1000
-		);
-		return () => {
-			clearInterval(interval);
-		};
-	}, []);
-
-	const addZero = n => {
-		return n < 10 ? "0" + n : n;
-	};
-
-	return (
-		<div className={classes.timerBox}>
-			<span>{`${addZero(timer.minutes)}:${addZero(timer.seconds)}`}</span>
-		</div>
-	);
-};
-
-export default RecordingTimer;

+ 0 - 773
frontend/src/components/MessageInputCustom/index.js

@@ -1,773 +0,0 @@
-import React, { useState, useEffect, useContext, useRef } from "react";
-import withWidth, { isWidthUp } from "@material-ui/core/withWidth";
-import "emoji-mart/css/emoji-mart.css";
-import { Picker } from "emoji-mart";
-import MicRecorder from "mic-recorder-to-mp3";
-import clsx from "clsx";
-import { isNil } from "lodash";
-
-import { makeStyles } from "@material-ui/core/styles";
-import Paper from "@material-ui/core/Paper";
-import InputBase from "@material-ui/core/InputBase";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import { green } from "@material-ui/core/colors";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-import IconButton from "@material-ui/core/IconButton";
-import MoodIcon from "@material-ui/icons/Mood";
-import SendIcon from "@material-ui/icons/Send";
-import CancelIcon from "@material-ui/icons/Cancel";
-import ClearIcon from "@material-ui/icons/Clear";
-import MicIcon from "@material-ui/icons/Mic";
-import CheckCircleOutlineIcon from "@material-ui/icons/CheckCircleOutline";
-import HighlightOffIcon from "@material-ui/icons/HighlightOff";
-import { FormControlLabel, Switch } from "@material-ui/core";
-import Autocomplete from "@material-ui/lab/Autocomplete";
-import { isString, isEmpty, isObject, has } from "lodash";
-
-import { i18n } from "../../translate/i18n";
-import api from "../../services/api";
-import axios from "axios";
-
-import RecordingTimer from "./RecordingTimer";
-import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { useLocalStorage } from "../../hooks/useLocalStorage";
-import toastError from "../../errors/toastError";
-
-import useQuickMessages from "../../hooks/useQuickMessages";
-
-const Mp3Recorder = new MicRecorder({ bitRate: 128 });
-
-const useStyles = makeStyles((theme) => ({
-  mainWrapper: {
-    backgroundColor: theme.palette.bordabox, //DARK MODE PLW DESIGN//
-    display: "flex",
-    flexDirection: "column",
-    alignItems: "center",
-    borderTop: "1px solid rgba(0, 0, 0, 0.12)",
-  },
-
-  newMessageBox: {
-    backgroundColor: theme.palette.newmessagebox, //DARK MODE PLW DESIGN//
-    width: "100%",
-    display: "flex",
-    padding: "7px",
-    alignItems: "center",
-  },
-
-  messageInputWrapper: {
-    padding: 6,
-    marginRight: 7,
-    backgroundColor: theme.palette.inputdigita, //DARK MODE PLW DESIGN//
-    display: "flex",
-    borderRadius: 20,
-    flex: 1,
-  },
-
-  messageInput: {
-    paddingLeft: 10,
-    flex: 1,
-    border: "none",
-  },
-
-  sendMessageIcons: {
-    color: "grey",
-  },
-
-  uploadInput: {
-    display: "none",
-  },
-
-  viewMediaInputWrapper: {
-    display: "flex",
-    padding: "10px 13px",
-    position: "relative",
-    justifyContent: "space-between",
-    alignItems: "center",
-    backgroundColor: "#eee",
-    borderTop: "1px solid rgba(0, 0, 0, 0.12)",
-  },
-
-  emojiBox: {
-    position: "absolute",
-    bottom: 63,
-    width: 40,
-    borderTop: "1px solid #e8e8e8",
-  },
-
-  circleLoading: {
-    color: green[500],
-    opacity: "70%",
-    position: "absolute",
-    top: "20%",
-    left: "50%",
-    marginLeft: -12,
-  },
-
-  audioLoading: {
-    color: green[500],
-    opacity: "70%",
-  },
-
-  recorderWrapper: {
-    display: "flex",
-    alignItems: "center",
-    alignContent: "middle",
-  },
-
-  cancelAudioIcon: {
-    color: "red",
-  },
-
-  sendAudioIcon: {
-    color: "green",
-  },
-
-  replyginMsgWrapper: {
-    display: "flex",
-    width: "100%",
-    alignItems: "center",
-    justifyContent: "center",
-    paddingTop: 8,
-    paddingLeft: 73,
-    paddingRight: 7,
-  },
-
-  replyginMsgContainer: {
-    flex: 1,
-    marginRight: 5,
-    overflowY: "hidden",
-    backgroundColor: "rgba(0, 0, 0, 0.05)",
-    borderRadius: "7.5px",
-    display: "flex",
-    position: "relative",
-  },
-
-  replyginMsgBody: {
-    padding: 10,
-    height: "auto",
-    display: "block",
-    whiteSpace: "pre-wrap",
-    overflow: "hidden",
-  },
-
-  replyginContactMsgSideColor: {
-    flex: "none",
-    width: "4px",
-    backgroundColor: "#35cd96",
-  },
-
-  replyginSelfMsgSideColor: {
-    flex: "none",
-    width: "4px",
-    backgroundColor: "#6bcbef",
-  },
-
-  messageContactName: {
-    display: "flex",
-    color: "#6bcbef",
-    fontWeight: 500,
-  },
-}));
-
-const EmojiOptions = (props) => {
-  const { disabled, showEmoji, setShowEmoji, handleAddEmoji } = props;
-  const classes = useStyles();
-  return (
-    <>
-      <IconButton
-        aria-label="emojiPicker"
-        component="span"
-        disabled={disabled}
-        onClick={(e) => setShowEmoji((prevState) => !prevState)}
-      >
-        <MoodIcon className={classes.sendMessageIcons} />
-      </IconButton>
-      {showEmoji ? (
-        <div className={classes.emojiBox}>
-          <Picker
-            perLine={16}
-            showPreview={false}
-            showSkinTones={false}
-            onSelect={handleAddEmoji}
-          />
-        </div>
-      ) : null}
-    </>
-  );
-};
-
-const SignSwitch = (props) => {
-  const { width, setSignMessage, signMessage } = props;
-  if (isWidthUp("md", width)) {
-    return (
-      <FormControlLabel
-        style={{ marginRight: 7, color: "gray" }}
-        label={i18n.t("messagesInput.signMessage")}
-        labelPlacement="start"
-        control={
-          <Switch
-            size="small"
-            checked={signMessage}
-            onChange={(e) => {
-              setSignMessage(e.target.checked);
-            }}
-            name="showAllTickets"
-            color="primary"
-          />
-        }
-      />
-    );
-  }
-  return null;
-};
-
-const FileInput = (props) => {
-  const { handleChangeMedias, disableOption } = props;
-  const classes = useStyles();
-  return (
-    <>
-      <input
-        multiple
-        type="file"
-        id="upload-button"
-        disabled={disableOption()}
-        className={classes.uploadInput}
-        onChange={handleChangeMedias}
-      />
-      <label htmlFor="upload-button">
-        <IconButton
-          aria-label="upload"
-          component="span"
-          disabled={disableOption()}
-        >
-          <AttachFileIcon className={classes.sendMessageIcons} />
-        </IconButton>
-      </label>
-    </>
-  );
-};
-
-const ActionButtons = (props) => {
-  const {
-    inputMessage,
-    loading,
-    recording,
-    ticketStatus,
-    handleSendMessage,
-    handleCancelAudio,
-    handleUploadAudio,
-    handleStartRecording,
-  } = props;
-  const classes = useStyles();
-  if (inputMessage) {
-    return (
-      <IconButton
-        aria-label="sendMessage"
-        component="span"
-        onClick={handleSendMessage}
-        disabled={loading}
-      >
-        <SendIcon className={classes.sendMessageIcons} />
-      </IconButton>
-    );
-  } else if (recording) {
-    return (
-      <div className={classes.recorderWrapper}>
-        <IconButton
-          aria-label="cancelRecording"
-          component="span"
-          fontSize="large"
-          disabled={loading}
-          onClick={handleCancelAudio}
-        >
-          <HighlightOffIcon className={classes.cancelAudioIcon} />
-        </IconButton>
-        {loading ? (
-          <div>
-            <CircularProgress className={classes.audioLoading} />
-          </div>
-        ) : (
-          <RecordingTimer />
-        )}
-
-        <IconButton
-          aria-label="sendRecordedAudio"
-          component="span"
-          onClick={handleUploadAudio}
-          disabled={loading}
-        >
-          <CheckCircleOutlineIcon className={classes.sendAudioIcon} />
-        </IconButton>
-      </div>
-    );
-  } else {
-    return (
-      <IconButton
-        aria-label="showRecorder"
-        component="span"
-        disabled={loading || ticketStatus !== "open"}
-        onClick={handleStartRecording}
-      >
-        <MicIcon className={classes.sendMessageIcons} />
-      </IconButton>
-    );
-  }
-};
-
-const CustomInput = (props) => {
-  const {
-    loading,
-    inputRef,
-    ticketStatus,
-    inputMessage,
-    setInputMessage,
-    handleSendMessage,
-    handleInputPaste,
-    disableOption,
-    handleQuickAnswersClick,
-  } = props;
-  const classes = useStyles();
-  const [quickMessages, setQuickMessages] = useState([]);
-  const [options, setOptions] = useState([]);
-  const [popupOpen, setPopupOpen] = useState(false);
-
-  const { user } = useContext(AuthContext);
-
-  const { list: listQuickMessages } = useQuickMessages();
-
-  useEffect(() => {
-    async function fetchData() {
-      const companyId = localStorage.getItem("companyId");
-      const messages = await listQuickMessages({ companyId, userId: user.id });
-      const options = messages.map((m) => {
-        let truncatedMessage = m.message;
-        if (isString(truncatedMessage) && truncatedMessage.length > 35) {
-          truncatedMessage = m.message.substring(0, 35) + "...";
-        }
-        return {
-          value: m.message,
-          label: `/${m.shortcode} - ${truncatedMessage}`,
-          mediaPath: m.mediaPath,
-        };
-      });
-      setQuickMessages(options);
-    }
-    fetchData();
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, []);
-
-  useEffect(() => {
-    if (
-      isString(inputMessage) &&
-      !isEmpty(inputMessage) &&
-      inputMessage.length > 1
-    ) {
-      const firstWord = inputMessage.charAt(0);
-      setPopupOpen(firstWord.indexOf("/") > -1);
-
-      const filteredOptions = quickMessages.filter(
-        (m) => m.label.indexOf(inputMessage) > -1
-      );
-      setOptions(filteredOptions);
-    } else {
-      setPopupOpen(false);
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [inputMessage]);
-
-  const onKeyPress = (e) => {
-    if (loading || e.shiftKey) return;
-    else if (e.key === "Enter") {
-      handleSendMessage();
-    }
-  };
-
-  const onPaste = (e) => {
-    if (ticketStatus === "open") {
-      handleInputPaste(e);
-    }
-  };
-
-  const renderPlaceholder = () => {
-    if (ticketStatus === "open") {
-      return i18n.t("messagesInput.placeholderOpen");
-    }
-    return i18n.t("messagesInput.placeholderClosed");
-  };
-
-
-  const setInputRef = (input) => {
-    if (input) {
-      input.focus();
-      inputRef.current = input;
-    }
-  };
-
-  return (
-    <div className={classes.messageInputWrapper}>
-      <Autocomplete
-        freeSolo
-        open={popupOpen}
-        id="grouped-demo"
-        value={inputMessage}
-        options={options}
-        closeIcon={null}
-        getOptionLabel={(option) => {
-          if (isObject(option)) {
-            return option.label;
-          } else {
-            return option;
-          }
-        }}
-        onChange={(event, opt) => {
-         
-          if (isObject(opt) && has(opt, "value") && isNil(opt.mediaPath)) {
-            setInputMessage(opt.value);
-            setTimeout(() => {
-              inputRef.current.scrollTop = inputRef.current.scrollHeight;
-            }, 200);
-          } else if (isObject(opt) && has(opt, "value") && !isNil(opt.mediaPath)) {
-            handleQuickAnswersClick(opt);
-
-            setTimeout(() => {
-              inputRef.current.scrollTop = inputRef.current.scrollHeight;
-            }, 200);
-          }
-        }}
-        onInputChange={(event, opt, reason) => {
-          if (reason === "input") {
-            setInputMessage(event.target.value);
-          }
-        }}
-        onPaste={onPaste}
-        onKeyPress={onKeyPress}
-        style={{ width: "100%" }}
-        renderInput={(params) => {
-          const { InputLabelProps, InputProps, ...rest } = params;
-          return (
-            <InputBase
-              {...params.InputProps}
-              {...rest}
-              disabled={disableOption()}
-              inputRef={setInputRef}
-              placeholder={renderPlaceholder()}
-              multiline
-              className={classes.messageInput}
-              maxRows={5}
-            />
-          );
-        }}
-      />
-    </div>
-  );
-};
-
-const MessageInputCustom = (props) => {
-  const { ticketStatus, ticketId } = props;
-  const classes = useStyles();
-
-  const [medias, setMedias] = useState([]);
-  const [inputMessage, setInputMessage] = useState("");
-  const [showEmoji, setShowEmoji] = useState(false);
-  const [loading, setLoading] = useState(false);
-  const [recording, setRecording] = useState(false);
-  const inputRef = useRef();
-  const { setReplyingMessage, replyingMessage } =
-    useContext(ReplyMessageContext);
-  const { user } = useContext(AuthContext);
-
-  const [signMessage, setSignMessage] = useLocalStorage("signOption", true);
-
-  useEffect(() => {
-    inputRef.current.focus();
-  }, [replyingMessage]);
-
-  useEffect(() => {
-    inputRef.current.focus();
-    return () => {
-      setInputMessage("");
-      setShowEmoji(false);
-      setMedias([]);
-      setReplyingMessage(null);
-    };
-  }, [ticketId, setReplyingMessage]);
-
-  // const handleChangeInput = e => {
-  // 	if (isObject(e) && has(e, 'value')) {
-  // 		setInputMessage(e.value);
-  // 	} else {
-  // 		setInputMessage(e.target.value)
-  // 	}
-  // };
-
-  const handleAddEmoji = (e) => {
-    let emoji = e.native;
-    setInputMessage((prevState) => prevState + emoji);
-  };
-
-  const handleChangeMedias = (e) => {
-    if (!e.target.files) {
-      return;
-    }
-
-    const selectedMedias = Array.from(e.target.files);
-    setMedias(selectedMedias);
-  };
-
-  const handleInputPaste = (e) => {
-    if (e.clipboardData.files[0]) {
-      setMedias([e.clipboardData.files[0]]);
-    }
-  };
-
-  const handleUploadQuickMessageMedia = async (blob, message) => {
-    setLoading(true);
-    try {
-      const extension = blob.type.split("/")[1];
-
-      const formData = new FormData();
-      const filename = `${new Date().getTime()}.${extension}`;
-      formData.append("medias", blob, filename);
-      formData.append("body",  message);
-      formData.append("fromMe", true);
-
-      await api.post(`/messages/${ticketId}`, formData);
-    } catch (err) {
-      toastError(err);
-      setLoading(false);
-    }
-    setLoading(false);
-  };
-  
-  const handleQuickAnswersClick = async (value) => {
-    if (value.mediaPath) {
-      try {
-        const { data } = await axios.get(value.mediaPath, {
-          responseType: "blob",
-        });
-
-        handleUploadQuickMessageMedia(data, value.value);
-        setInputMessage("");
-        return;
-        //  handleChangeMedias(response)
-      } catch (err) {
-        toastError(err);
-      }
-    }
-
-    setInputMessage("");
-    setInputMessage(value.value);
-  };
-
-  const handleUploadMedia = async (e) => {
-    setLoading(true);
-    e.preventDefault();
-
-    const formData = new FormData();
-    formData.append("fromMe", true);
-    medias.forEach((media) => {
-      formData.append("medias", media);
-      formData.append("body", media.name);
-    });
-
-    try {
-      await api.post(`/messages/${ticketId}`, formData);
-    } catch (err) {
-      toastError(err);
-    }
-
-    setLoading(false);
-    setMedias([]);
-  };
-
-  const handleSendMessage = async () => {
-    if (inputMessage.trim() === "") return;
-    setLoading(true);
-
-    const message = {
-      read: 1,
-      fromMe: true,
-      mediaUrl: "",
-      body: signMessage
-        ? `*${user?.name}:*\n${inputMessage.trim()}`
-        : inputMessage.trim(),
-      quotedMsg: replyingMessage,
-    };
-    try {
-      await api.post(`/messages/${ticketId}`, message);
-    } catch (err) {
-      toastError(err);
-    }
-
-    setInputMessage("");
-    setShowEmoji(false);
-    setLoading(false);
-    setReplyingMessage(null);
-  };
-
-  const handleStartRecording = async () => {
-    setLoading(true);
-    try {
-      await navigator.mediaDevices.getUserMedia({ audio: true });
-      await Mp3Recorder.start();
-      setRecording(true);
-      setLoading(false);
-    } catch (err) {
-      toastError(err);
-      setLoading(false);
-    }
-  };
-
-  const handleUploadAudio = async () => {
-    setLoading(true);
-    try {
-      const [, blob] = await Mp3Recorder.stop().getMp3();
-      if (blob.size < 10000) {
-        setLoading(false);
-        setRecording(false);
-        return;
-      }
-
-      const formData = new FormData();
-      const filename = `audio-record-site-${new Date().getTime()}.mp3`;
-      formData.append("medias", blob, filename);
-      formData.append("body", filename);
-      formData.append("fromMe", true);
-
-      await api.post(`/messages/${ticketId}`, formData);
-    } catch (err) {
-      toastError(err);
-    }
-
-    setRecording(false);
-    setLoading(false);
-  };
-
-  const handleCancelAudio = async () => {
-    try {
-      await Mp3Recorder.stop().getMp3();
-      setRecording(false);
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  const disableOption = () => {
-    return loading || recording || ticketStatus !== "open";
-  };
-
-  const renderReplyingMessage = (message) => {
-    return (
-      <div className={classes.replyginMsgWrapper}>
-        <div className={classes.replyginMsgContainer}>
-          <span
-            className={clsx(classes.replyginContactMsgSideColor, {
-              [classes.replyginSelfMsgSideColor]: !message.fromMe,
-            })}
-          ></span>
-          <div className={classes.replyginMsgBody}>
-            {!message.fromMe && (
-              <span className={classes.messageContactName}>
-                {message.contact?.name}
-              </span>
-            )}
-            {message.body}
-          </div>
-        </div>
-        <IconButton
-          aria-label="showRecorder"
-          component="span"
-          disabled={loading || ticketStatus !== "open"}
-          onClick={() => setReplyingMessage(null)}
-        >
-          <ClearIcon className={classes.sendMessageIcons} />
-        </IconButton>
-      </div>
-    );
-  };
-
-  if (medias.length > 0)
-    return (
-      <Paper elevation={0} square className={classes.viewMediaInputWrapper}>
-        <IconButton
-          aria-label="cancel-upload"
-          component="span"
-          onClick={(e) => setMedias([])}
-        >
-          <CancelIcon className={classes.sendMessageIcons} />
-        </IconButton>
-
-        {loading ? (
-          <div>
-            <CircularProgress className={classes.circleLoading} />
-          </div>
-        ) : (
-          <span>
-            {medias[0]?.name}
-            {/* <img src={media.preview} alt=""></img> */}
-          </span>
-        )}
-        <IconButton
-          aria-label="send-upload"
-          component="span"
-          onClick={handleUploadMedia}
-          disabled={loading}
-        >
-          <SendIcon className={classes.sendMessageIcons} />
-        </IconButton>
-      </Paper>
-    );
-  else {
-    return (
-      <Paper square elevation={0} className={classes.mainWrapper}>
-        {replyingMessage && renderReplyingMessage(replyingMessage)}
-        <div className={classes.newMessageBox}>
-          <EmojiOptions
-            disabled={disableOption()}
-            handleAddEmoji={handleAddEmoji}
-            showEmoji={showEmoji}
-            setShowEmoji={setShowEmoji}
-          />
-
-          <FileInput
-            disableOption={disableOption}
-            handleChangeMedias={handleChangeMedias}
-          />
-
-          <SignSwitch
-            width={props.width}
-            setSignMessage={setSignMessage}
-            signMessage={signMessage}
-          />
-
-          <CustomInput
-            loading={loading}
-            inputRef={inputRef}
-            ticketStatus={ticketStatus}
-            inputMessage={inputMessage}
-            setInputMessage={setInputMessage}
-            // handleChangeInput={handleChangeInput}
-            handleSendMessage={handleSendMessage}
-            handleInputPaste={handleInputPaste}
-            disableOption={disableOption}
-            handleQuickAnswersClick={handleQuickAnswersClick}
-          />
-
-          <ActionButtons
-            inputMessage={inputMessage}
-            loading={loading}
-            recording={recording}
-            ticketStatus={ticketStatus}
-            handleSendMessage={handleSendMessage}
-            handleCancelAudio={handleCancelAudio}
-            handleUploadAudio={handleUploadAudio}
-            handleStartRecording={handleStartRecording}
-          />
-        </div>
-      </Paper>
-    );
-  }
-};
-
-export default withWidth()(MessageInputCustom);

+ 0 - 71
frontend/src/components/MessageOptionsMenu/index.js

@@ -1,71 +0,0 @@
-import React, { useState, useContext } from "react";
-
-import MenuItem from "@material-ui/core/MenuItem";
-
-import { i18n } from "../../translate/i18n";
-import api from "../../services/api";
-import ConfirmationModal from "../ConfirmationModal";
-import { Menu } from "@material-ui/core";
-import { ReplyMessageContext } from "../../context/ReplyingMessage/ReplyingMessageContext";
-import toastError from "../../errors/toastError";
-
-const MessageOptionsMenu = ({ message, menuOpen, handleClose, anchorEl }) => {
-	const { setReplyingMessage } = useContext(ReplyMessageContext);
-	const [confirmationOpen, setConfirmationOpen] = useState(false);
-
-	const handleDeleteMessage = async () => {
-		try {
-			await api.delete(`/messages/${message.id}`);
-		} catch (err) {
-			toastError(err);
-		}
-	};
-
-	const hanldeReplyMessage = () => {
-		setReplyingMessage(message);
-		handleClose();
-	};
-
-	const handleOpenConfirmationModal = e => {
-		setConfirmationOpen(true);
-		handleClose();
-	};
-
-	return (
-		<>
-			<ConfirmationModal
-				title={i18n.t("messageOptionsMenu.confirmationModal.title")}
-				open={confirmationOpen}
-				onClose={setConfirmationOpen}
-				onConfirm={handleDeleteMessage}
-			>
-				{i18n.t("messageOptionsMenu.confirmationModal.message")}
-			</ConfirmationModal>
-			<Menu
-				anchorEl={anchorEl}
-				getContentAnchorEl={null}
-				anchorOrigin={{
-					vertical: "bottom",
-					horizontal: "right",
-				}}
-				transformOrigin={{
-					vertical: "top",
-					horizontal: "right",
-				}}
-				open={menuOpen}
-				onClose={handleClose}
-			>
-				{message.fromMe && (
-					<MenuItem onClick={handleOpenConfirmationModal}>
-						{i18n.t("messageOptionsMenu.delete")}
-					</MenuItem>
-				)}
-				<MenuItem onClick={hanldeReplyMessage}>
-					{i18n.t("messageOptionsMenu.reply")}
-				</MenuItem>
-			</Menu>
-		</>
-	);
-};
-
-export default MessageOptionsMenu;

+ 0 - 66
frontend/src/components/MessageVariablesPicker/index.js

@@ -1,66 +0,0 @@
-import React from "react";
-import { Chip, makeStyles } from "@material-ui/core";
-import { i18n } from "../../translate/i18n";
-import OutlinedDiv from "../OutlinedDiv";
-
-const useStyles = makeStyles(theme => ({
-    chip: {
-        margin: theme.spacing(0.5),
-        cursor: "pointer"
-    }
-}));
-
-const MessageVariablesPicker = ({ onClick, disabled }) => {
-    const classes = useStyles();
-
-    const handleClick = (e, value) => {
-        e.preventDefault();
-        if (disabled) return;
-        onClick(value);
-    };
-
-    const msgVars = [
-        {
-            name: i18n.t("messageVariablesPicker.vars.contactFirstName"),
-            value: "{{firstName}}"
-        },
-        {
-            name: i18n.t("messageVariablesPicker.vars.contactName"),
-            value: "{{name}} "
-        },
-        {
-            name: i18n.t("messageVariablesPicker.vars.greeting"),
-            value: "{{ms}} "
-        },
-        {
-            name: i18n.t("messageVariablesPicker.vars.protocolNumber"),
-            value: "{{protocol}} "
-        },
-        {
-            name: i18n.t("messageVariablesPicker.vars.hour"),
-            value: "{{hora}} "
-        },
-    ];
-
-    return (
-        <OutlinedDiv
-            margin="dense"
-            fullWidth
-            label={i18n.t("messageVariablesPicker.label")}
-            disabled={disabled}
-        >
-            {msgVars.map(msgVar => (
-                <Chip
-                    key={msgVar.value}
-                    onMouseDown={e => handleClick(e, msgVar.value)}
-                    label={msgVar.name}
-                    size="small"
-                    className={classes.chip}
-                    color="primary"
-                />
-            ))}
-        </OutlinedDiv>
-    );
-};
-
-export default MessageVariablesPicker;

+ 0 - 837
frontend/src/components/MessagesList/index.js

@@ -1,837 +0,0 @@
-import React, { useState, useEffect, useReducer, useRef, useContext } from "react";
-
-import { isSameDay, parseISO, format } from "date-fns";
-import clsx from "clsx";
-
-import { green } from "@material-ui/core/colors";
-import {
-  Button,
-  CircularProgress,
-  Divider,
-  IconButton,
-  makeStyles,
-} from "@material-ui/core";
-
-import {
-  AccessTime,
-  Block,
-  Done,
-  DoneAll,
-  ExpandMore,
-  GetApp,
-} from "@material-ui/icons";
-
-import MarkdownWrapper from "../MarkdownWrapper";
-import ModalImageCors from "../ModalImageCors";
-import MessageOptionsMenu from "../MessageOptionsMenu";
-import whatsBackground from "../../assets/wa-background.png";
-import LocationPreview from "../LocationPreview";
-
-import whatsBackgroundDark from "../../assets/wa-background-dark.png"; //DARK MODE PLW DESIGN//
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { SocketContext } from "../../context/Socket/SocketContext";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles((theme) => ({
-  messagesListWrapper: {
-    overflow: "hidden",
-    position: "relative",
-    display: "flex",
-    flexDirection: "column",
-    flexGrow: 1,
-    width: "100%",
-    minWidth: 300,
-    minHeight: 200,
-  },
-
-  messagesList: {
-    backgroundImage: theme.mode === 'light' ? `url(${whatsBackground})` : `url(${whatsBackgroundDark})`, //DARK MODE PLW DESIGN//
-    display: "flex",
-    flexDirection: "column",
-    flexGrow: 1,
-    padding: "20px 20px 20px 20px",
-    overflowY: "scroll",
-    ...theme.scrollbarStyles,
-  },
-
-  circleLoading: {
-    color: green[500],
-    position: "absolute",
-    opacity: "70%",
-    top: 0,
-    left: "50%",
-    marginTop: 12,
-  },
-
-  messageLeft: {
-    marginRight: 20,
-    marginTop: 2,
-    minWidth: 100,
-    maxWidth: 600,
-    height: "auto",
-    display: "block",
-    position: "relative",
-    "&:hover #messageActionsButton": {
-      display: "flex",
-      position: "absolute",
-      top: 0,
-      right: 0,
-    },
-
-    whiteSpace: "pre-wrap",
-    backgroundColor: "#ffffff",
-    color: "#303030",
-    alignSelf: "flex-start",
-    borderTopLeftRadius: 0,
-    borderTopRightRadius: 8,
-    borderBottomLeftRadius: 8,
-    borderBottomRightRadius: 8,
-    paddingLeft: 5,
-    paddingRight: 5,
-    paddingTop: 5,
-    paddingBottom: 0,
-    boxShadow: "0 1px 1px #b3b3b3",
-  },
-
-  quotedContainerLeft: {
-    margin: "-3px -80px 6px -6px",
-    overflow: "hidden",
-    backgroundColor: "#f0f0f0",
-    borderRadius: "7.5px",
-    display: "flex",
-    position: "relative",
-  },
-
-  quotedMsg: {
-    padding: 10,
-    maxWidth: 300,
-    height: "auto",
-    display: "block",
-    whiteSpace: "pre-wrap",
-    overflow: "hidden",
-  },
-
-  quotedSideColorLeft: {
-    flex: "none",
-    width: "4px",
-    backgroundColor: "#6bcbef",
-  },
-
-  messageRight: {
-    marginLeft: 20,
-    marginTop: 2,
-    minWidth: 100,
-    maxWidth: 600,
-    height: "auto",
-    display: "block",
-    position: "relative",
-    "&:hover #messageActionsButton": {
-      display: "flex",
-      position: "absolute",
-      top: 0,
-      right: 0,
-    },
-
-    whiteSpace: "pre-wrap",
-    backgroundColor: "#dcf8c6",
-    color: "#303030",
-    alignSelf: "flex-end",
-    borderTopLeftRadius: 8,
-    borderTopRightRadius: 8,
-    borderBottomLeftRadius: 8,
-    borderBottomRightRadius: 0,
-    paddingLeft: 5,
-    paddingRight: 5,
-    paddingTop: 5,
-    paddingBottom: 0,
-    boxShadow: "0 1px 1px #b3b3b3",
-  },
-
-  quotedContainerRight: {
-    margin: "-3px -80px 6px -6px",
-    overflowY: "hidden",
-    backgroundColor: "#cfe9ba",
-    borderRadius: "7.5px",
-    display: "flex",
-    position: "relative",
-  },
-
-  quotedMsgRight: {
-    padding: 10,
-    maxWidth: 300,
-    height: "auto",
-    whiteSpace: "pre-wrap",
-  },
-
-  quotedSideColorRight: {
-    flex: "none",
-    width: "4px",
-    backgroundColor: "#35cd96",
-  },
-
-  messageActionsButton: {
-    display: "none",
-    position: "relative",
-    color: "#999",
-    zIndex: 1,
-    backgroundColor: "inherit",
-    opacity: "90%",
-    "&:hover, &.Mui-focusVisible": { backgroundColor: "inherit" },
-  },
-
-  messageContactName: {
-    display: "flex",
-    color: "#6bcbef",
-    fontWeight: 500,
-  },
-
-  textContentItem: {
-    overflowWrap: "break-word",
-    padding: "3px 80px 6px 6px",
-  },
-  
-  textContentItemEdited: {
-    overflowWrap: "break-word",
-    padding: "3px 120px 6px 6px",
-  },
-
-  textContentItemDeleted: {
-    fontStyle: "italic",
-    color: "rgba(0, 0, 0, 0.36)",
-    overflowWrap: "break-word",
-    padding: "3px 80px 6px 6px",
-  },
-
-  messageMedia: {
-    objectFit: "cover",
-    width: 250,
-    height: 200,
-    borderTopLeftRadius: 8,
-    borderTopRightRadius: 8,
-    borderBottomLeftRadius: 8,
-    borderBottomRightRadius: 8,
-  },
-
-  timestamp: {
-    fontSize: 11,
-    position: "absolute",
-    bottom: 0,
-    right: 5,
-    color: "#999",
-  },
-
-  dailyTimestamp: {
-    alignItems: "center",
-    textAlign: "center",
-    alignSelf: "center",
-    width: "110px",
-    backgroundColor: "#e1f3fb",
-    margin: "10px",
-    borderRadius: "10px",
-    boxShadow: "0 1px 1px #b3b3b3",
-  },
-
-  dailyTimestampText: {
-    color: "#808888",
-    padding: 8,
-    alignSelf: "center",
-    marginLeft: "0px",
-  },
-
-  ackIcons: {
-    fontSize: 18,
-    verticalAlign: "middle",
-    marginLeft: 4,
-  },
-
-  deletedIcon: {
-    fontSize: 18,
-    verticalAlign: "middle",
-    marginRight: 4,
-  },
-
-  ackDoneAllIcon: {
-    color: green[500],
-    fontSize: 18,
-    verticalAlign: "middle",
-    marginLeft: 4,
-  },
-
-  downloadMedia: {
-    display: "flex",
-    alignItems: "center",
-    justifyContent: "center",
-    backgroundColor: "inherit",
-    padding: 10,
-  },
-}));
-
-const reducer = (state, action) => {
-  if (action.type === "LOAD_MESSAGES") {
-    const messages = action.payload;
-    const newMessages = [];
-
-    messages.forEach((message) => {
-      const messageIndex = state.findIndex((m) => m.id === message.id);
-      if (messageIndex !== -1) {
-        state[messageIndex] = message;
-      } else {
-        newMessages.push(message);
-      }
-    });
-
-    return [...newMessages, ...state];
-  }
-
-  if (action.type === "ADD_MESSAGE") {
-    const newMessage = action.payload;
-    const messageIndex = state.findIndex((m) => m.id === newMessage.id);
-
-    if (messageIndex !== -1) {
-      state[messageIndex] = newMessage;
-    } else {
-      state.push(newMessage);
-    }
-
-    return [...state];
-  }
-
-  if (action.type === "UPDATE_MESSAGE") {
-    const messageToUpdate = action.payload;
-    const messageIndex = state.findIndex((m) => m.id === messageToUpdate.id);
-
-    if (messageIndex !== -1) {
-      state[messageIndex] = messageToUpdate;
-    }
-
-    return [...state];
-  }
-
-  if (action.type === "RESET") {
-    return [];
-  }
-};
-
-const MessagesList = ({ ticket, ticketId, isGroup }) => {
-  const classes = useStyles();
-
-  const [messagesList, dispatch] = useReducer(reducer, []);
-  const [pageNumber, setPageNumber] = useState(1);
-  const [hasMore, setHasMore] = useState(false);
-  const [loading, setLoading] = useState(false);
-  const lastMessageRef = useRef();
-
-  const [selectedMessage, setSelectedMessage] = useState({});
-  const [anchorEl, setAnchorEl] = useState(null);
-  const messageOptionsMenuOpen = Boolean(anchorEl);
-  const currentTicketId = useRef(ticketId);
-
-  const socketManager = useContext(SocketContext);
-
-  useEffect(() => {
-    dispatch({ type: "RESET" });
-    setPageNumber(1);
-
-    currentTicketId.current = ticketId;
-  }, [ticketId]);
-
-  useEffect(() => {
-    setLoading(true);
-    const delayDebounceFn = setTimeout(() => {
-      const fetchMessages = async () => {
-        if (ticketId === undefined) return;
-        try {
-          const { data } = await api.get("/messages/" + ticketId, {
-            params: { pageNumber },
-          });
-
-          if (currentTicketId.current === ticketId) {
-            dispatch({ type: "LOAD_MESSAGES", payload: data.messages });
-            setHasMore(data.hasMore);
-            setLoading(false);
-          }
-
-          if (pageNumber === 1 && data.messages.length > 1) {
-            scrollToBottom();
-          }
-        } catch (err) {
-          setLoading(false);
-          toastError(err);
-        }
-      };
-      fetchMessages();
-    }, 500);
-    return () => {
-      clearTimeout(delayDebounceFn);
-    };
-  }, [pageNumber, ticketId]);
-
-  useEffect(() => {
-    const companyId = localStorage.getItem("companyId");
-    const socket = socketManager.getSocket(companyId);
-
-    socket.on("ready", () => socket.emit("joinChatBox", `${ticket.id}`));
-
-    socket.on(`company-${companyId}-appMessage`, (data) => {
-      if (data.action === "create" && data.message.ticketId === currentTicketId.current) {
-        dispatch({ type: "ADD_MESSAGE", payload: data.message });
-        scrollToBottom();
-      }
-
-      if (data.action === "update" && data.message.ticketId === currentTicketId.current) {
-        dispatch({ type: "UPDATE_MESSAGE", payload: data.message });
-      }
-    });
-
-    return () => {
-      socket.disconnect();
-    };
-  }, [ticketId, ticket, socketManager]);
-
-  const loadMore = () => {
-    setPageNumber((prevPageNumber) => prevPageNumber + 1);
-  };
-
-  const scrollToBottom = () => {
-    if (lastMessageRef.current) {
-      lastMessageRef.current.scrollIntoView({});
-    }
-  };
-
-  const handleScroll = (e) => {
-    if (!hasMore) return;
-    const { scrollTop } = e.currentTarget;
-
-    if (scrollTop === 0) {
-      document.getElementById("messagesList").scrollTop = 1;
-    }
-
-    if (loading) {
-      return;
-    }
-
-    if (scrollTop < 50) {
-      loadMore();
-    }
-  };
-
-  const handleOpenMessageOptionsMenu = (e, message) => {
-    setAnchorEl(e.currentTarget);
-    setSelectedMessage(message);
-  };
-
-  const handleCloseMessageOptionsMenu = (e) => {
-    setAnchorEl(null);
-  };
-
-  const checkMessageMedia = (message) => {
-
-    if (message.mediaType === "locationMessage" && message.body.split('|').length >= 2) {
-      let locationParts = message.body.split('|')
-      let imageLocation = locationParts[0]
-      let linkLocation = locationParts[1]
-
-      let descriptionLocation = null
-
-      if (locationParts.length > 2)
-        descriptionLocation = message.body.split('|')[2]
-
-      return <LocationPreview image={imageLocation} link={linkLocation} description={descriptionLocation} />
-    }
-    /* else if (message.mediaType === "vcard") {
-      let array = message.body.split("\n");
-      let obj = [];
-      let contact = "";
-      for (let index = 0; index < array.length; index++) {
-        const v = array[index];
-        let values = v.split(":");
-        for (let ind = 0; ind < values.length; ind++) {
-          if (values[ind].indexOf("+") !== -1) {
-            obj.push({ number: values[ind] });
-          }
-          if (values[ind].indexOf("FN") !== -1) {
-            contact = values[ind + 1];
-          }
-        }
-      }
-      return <VcardPreview contact={contact} numbers={obj[0].number} />
-    } */
-    /*else if (message.mediaType === "multi_vcard") {
-      console.log("multi_vcard")
-      console.log(message)
-    	
-      if(message.body !== null && message.body !== "") {
-        let newBody = JSON.parse(message.body)
-        return (
-          <>
-            {
-            newBody.map(v => (
-              <VcardPreview contact={v.name} numbers={v.number} />
-            ))
-            }
-          </>
-        )
-      } else return (<></>)
-    }*/
-    else if (message.mediaType === "image") {
-      return <ModalImageCors imageUrl={message.mediaUrl} />;
-    } else if (message.mediaType === "audio") {
-      return (
-        <audio controls>
-          <source src={message.mediaUrl} type="audio/ogg"></source>
-        </audio>
-      );
-    } else if (message.mediaType === "video") {
-      return (
-        <video
-          className={classes.messageMedia}
-          src={message.mediaUrl}
-          controls
-        />
-      );
-    } else {
-      return (
-        <>
-          <div className={classes.downloadMedia}>
-            <Button
-              startIcon={<GetApp />}
-              color="primary"
-              variant="outlined"
-              target="_blank"
-              href={message.mediaUrl}
-            >
-              {i18n.t("messagesList.header.buttons.download")}
-            </Button>
-          </div>
-          <div style={{marginBottom: message.body === "" ? 8 : 0}}>
-            <Divider />
-          </div>
-        </>
-      );
-    }
-  };
-
-  const renderMessageAck = (message) => {
-    if (message.ack === 1) {
-      return <AccessTime fontSize="small" className={classes.ackIcons} />;
-    }
-    if (message.ack === 2) {
-      return <Done fontSize="small" className={classes.ackIcons} />;
-    }
-    if (message.ack === 3) {
-      return <DoneAll fontSize="small" className={classes.ackIcons} />;
-    }
-    if (message.ack === 4 || message.ack === 5) {
-      return <DoneAll fontSize="small" className={classes.ackDoneAllIcon} />;
-    }
-  };
-
-  const renderDailyTimestamps = (message, index) => {
-    if (index === 0) {
-      return (
-        <span
-          className={classes.dailyTimestamp}
-          key={`timestamp-${message.id}`}
-        >
-          <div className={classes.dailyTimestampText}>
-            {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
-          </div>
-        </span>
-      );
-    }
-    if (index < messagesList.length - 1) {
-      let messageDay = parseISO(messagesList[index].createdAt);
-      let previousMessageDay = parseISO(messagesList[index - 1].createdAt);
-
-      if (!isSameDay(messageDay, previousMessageDay)) {
-        return (
-          <span
-            className={classes.dailyTimestamp}
-            key={`timestamp-${message.id}`}
-          >
-            <div className={classes.dailyTimestampText}>
-              {format(parseISO(messagesList[index].createdAt), "dd/MM/yyyy")}
-            </div>
-          </span>
-        );
-      }
-    }
-    if (index === messagesList.length - 1) {
-      return (
-        <div
-          key={`ref-${message.createdAt}`}
-          ref={lastMessageRef}
-          style={{ float: "left", clear: "both" }}
-        />
-      );
-    }
-  };
-
-  const renderNumberTicket = (message, index) => {
-    if (index < messagesList.length && index > 0) {
-
-      let messageTicket = message.ticketId;
-      let connectionName = message.ticket?.whatsapp?.name;
-      let previousMessageTicket = messagesList[index - 1].ticketId;
-
-      if (messageTicket !== previousMessageTicket) {
-        return (
-          <center>
-            <div className={classes.ticketNunberClosed}>
-              Conversa encerrada: {format(parseISO(messagesList[index - 1].createdAt), "dd/MM/yyyy HH:mm:ss")}
-            </div>
-
-            <div className={classes.ticketNunberOpen}>
-              Conversa iniciada: {format(parseISO(message.createdAt), "dd/MM/yyyy HH:mm:ss")}
-            </div>
-          </center>
-        );
-      }
-    }
-  };
-
-  const renderMessageDivider = (message, index) => {
-    if (index < messagesList.length && index > 0) {
-      let messageUser = messagesList[index].fromMe;
-      let previousMessageUser = messagesList[index - 1].fromMe;
-
-      if (messageUser !== previousMessageUser) {
-        return (
-          <span style={{ marginTop: 16 }} key={`divider-${message.id}`}></span>
-        );
-      }
-    }
-  };
-
-  const renderQuotedMessage = (message) => {
-    return (
-      <div
-        className={clsx(classes.quotedContainerLeft, {
-          [classes.quotedContainerRight]: message.fromMe,
-        })}
-      >
-        <span
-          className={clsx(classes.quotedSideColorLeft, {
-            [classes.quotedSideColorRight]: message.quotedMsg?.fromMe,
-          })}
-        ></span>
-        <div className={classes.quotedMsg}>
-          {!message.quotedMsg?.fromMe && (
-            <span className={classes.messageContactName}>
-              {message.quotedMsg?.contact?.name}
-            </span>
-          )}
-
-          {message.quotedMsg.mediaType === "audio"
-            && (
-              <div className={classes.downloadMedia}>
-                <audio controls>
-                  <source src={message.quotedMsg.mediaUrl} type="audio/ogg"></source>
-                </audio>
-              </div>
-            )
-          }
-          {message.quotedMsg.mediaType === "video"
-            && (
-              <video
-                className={classes.messageMedia}
-                src={message.quotedMsg.mediaUrl}
-                controls
-              />
-            )
-          }
-          {message.quotedMsg.mediaType === "application"
-            && (
-              <div className={classes.downloadMedia}>
-                <Button
-                  startIcon={<GetApp />}
-                  color="primary"
-                  variant="outlined"
-                  target="_blank"
-                  href={message.quotedMsg.mediaUrl}
-                >
-                  {i18n.t("messagesList.header.buttons.download")}
-                </Button>
-              </div>
-            )
-          }
-
-          {message.quotedMsg.mediaType === "image"
-            && (<ModalImageCors imageUrl={message.quotedMsg.mediaUrl} />)}
-
-          {message.quotedMsg.mediaType === "contactMessage"
-            && (
-                <span>{message.quotedMsg.body}</span>
-              )
-          }
-        </div>
-      </div>
-    );
-  };
-
-  const renderMessages = () => {
-    if (messagesList.length > 0) {
-      const viewMessagesList = messagesList.map((message, index) => {
-
-        if (message.mediaType === "call_log") {
-          return (
-            <React.Fragment key={message.id}>
-              {renderDailyTimestamps(message, index)}
-              {renderNumberTicket(message, index)}
-              {renderMessageDivider(message, index)}
-              <div className={classes.messageCenter}>
-                <IconButton
-                  variant="contained"
-                  size="small"
-                  id="messageActionsButton"
-                  disabled={message.isDeleted}
-                  className={classes.messageActionsButton}
-                  onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
-                >
-                  <ExpandMore />
-                </IconButton>
-                {isGroup && (
-                  <span className={classes.messageContactName}>
-                    {message.contact?.name}
-                  </span>
-                )}
-                <div>
-                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 17" width="20" height="17">
-                    <path fill="#df3333" d="M18.2 12.1c-1.5-1.8-5-2.7-8.2-2.7s-6.7 1-8.2 2.7c-.7.8-.3 2.3.2 2.8.2.2.3.3.5.3 1.4 0 3.6-.7 3.6-.7.5-.2.8-.5.8-1v-1.3c.7-1.2 5.4-1.2 6.4-.1l.1.1v1.3c0 .2.1.4.2.6.1.2.3.3.5.4 0 0 2.2.7 3.6.7.2 0 1.4-2 .5-3.1zM5.4 3.2l4.7 4.6 5.8-5.7-.9-.8L10.1 6 6.4 2.3h2.5V1H4.1v4.8h1.3V3.2z"></path>
-                  </svg> <span>{i18n.t("messagesList.lostCall")} {format(parseISO(message.createdAt), "HH:mm")}</span>
-                </div>
-              </div>
-            </React.Fragment>
-          );
-        }
-
-        if (!message.fromMe) {
-          return (
-            <React.Fragment key={message.id}>
-              {renderDailyTimestamps(message, index)}
-              {renderNumberTicket(message, index)}
-              {renderMessageDivider(message, index)}
-              <div className={classes.messageLeft}>
-                <IconButton
-                  variant="contained"
-                  size="small"
-                  id="messageActionsButton"
-                  disabled={message.isDeleted}
-                  className={classes.messageActionsButton}
-                  onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
-                >
-                  <ExpandMore />
-                </IconButton>
-                {isGroup && (
-                  <span className={classes.messageContactName}>
-                    {message.contact?.name}
-                  </span>
-                )}
-
-                {/* aviso de mensagem apagado pelo contato */}
-                {message.isDeleted && (
-                  <div>
-                    <span className={"message-deleted"}
-                    >{i18n.t("messagesList.deletedMessage")} &nbsp;
-                      <Block
-                        color="error"
-                        fontSize="small"
-                        className={classes.deletedIcon}
-                      />
-                    </span>
-                  </div>
-                )}
-
-                {(message.mediaUrl || message.mediaType === "locationMessage" || message.mediaType === "vcard"
-                  //|| message.mediaType === "multi_vcard" 
-                ) && checkMessageMedia(message)}
-                <div className={classes.textContentItem}>
-                  {message.quotedMsg && renderQuotedMessage(message)}
-                  <MarkdownWrapper>{message.mediaType === "locationMessage" ? null : message.body}</MarkdownWrapper>
-                  <span className={classes.timestamp}>
-				    {message.isEdited && <span>Editada </span>}
-                    {format(parseISO(message.createdAt), "HH:mm")}
-                  </span>
-                </div>
-              </div>
-            </React.Fragment>
-          );
-        } else {
-          return (
-            <React.Fragment key={message.id}>
-              {renderDailyTimestamps(message, index)}
-              {renderNumberTicket(message, index)}
-              {renderMessageDivider(message, index)}
-              <div className={classes.messageRight}>
-                <IconButton
-                  variant="contained"
-                  size="small"
-                  id="messageActionsButton"
-                  disabled={message.isDeleted}
-                  className={classes.messageActionsButton}
-                  onClick={(e) => handleOpenMessageOptionsMenu(e, message)}
-                >
-                  <ExpandMore />
-                </IconButton>
-                {(message.mediaUrl || message.mediaType === "locationMessage" || message.mediaType === "vcard"
-                  //|| message.mediaType === "multi_vcard" 
-                ) && checkMessageMedia(message)}
-                <div
-                  className={clsx(classes.textContentItem, {
-                    [classes.textContentItemDeleted]: message.isDeleted,
-					[classes.textContentItemEdited]: message.isEdited,
-                  })}
-                >
-                  {message.isDeleted && (
-                    <Block
-                      color="disabled"
-                      fontSize="small"
-                      className={classes.deletedIcon}
-                    />
-                  )}
-                  {message.quotedMsg && renderQuotedMessage(message)}
-                  <MarkdownWrapper>{message.mediaType === "locationMessage" ? null : message.body}</MarkdownWrapper>
-                  <span className={classes.timestamp}>
-				    {message.isEdited && <span>{i18n.t("messagesList.edited")}</span>}
-                    {format(parseISO(message.createdAt), "HH:mm")}
-                    {renderMessageAck(message)}
-                  </span>
-                </div>
-              </div>
-            </React.Fragment>
-          );
-        }
-      });
-      return viewMessagesList;
-    } else {
-      return <div>{i18n.t("messagesList.saudation")}</div>;
-    }
-  };
-
-  return (
-    <div className={classes.messagesListWrapper}>
-      <MessageOptionsMenu
-        message={selectedMessage}
-        anchorEl={anchorEl}
-        menuOpen={messageOptionsMenuOpen}
-        handleClose={handleCloseMessageOptionsMenu}
-      />
-      <div
-        id="messagesList"
-        className={classes.messagesList}
-        onScroll={handleScroll}
-      >
-        {messagesList.length > 0 ? renderMessages() : []}
-      </div>
-      {loading && (
-        <div>
-          <CircularProgress className={classes.circleLoading} />
-        </div>
-      )}
-    </div>
-  );
-};
-
-export default MessagesList;

+ 0 - 50
frontend/src/components/ModalImageCors/index.js

@@ -1,50 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-
-import ModalImage from "react-modal-image";
-import api from "../../services/api";
-
-const useStyles = makeStyles(theme => ({
-	messageMedia: {
-		objectFit: "cover",
-		width: 250,
-		height: 200,
-		borderTopLeftRadius: 8,
-		borderTopRightRadius: 8,
-		borderBottomLeftRadius: 8,
-		borderBottomRightRadius: 8,
-	},
-}));
-
-const ModalImageCors = ({ imageUrl }) => {
-	const classes = useStyles();
-	const [fetching, setFetching] = useState(true);
-	const [blobUrl, setBlobUrl] = useState("");
-
-	useEffect(() => {
-		if (!imageUrl) return;
-		const fetchImage = async () => {
-			const { data, headers } = await api.get(imageUrl, {
-				responseType: "blob",
-			});
-			const url = window.URL.createObjectURL(
-				new Blob([data], { type: headers["content-type"] })
-			);
-			setBlobUrl(url);
-			setFetching(false);
-		};
-		fetchImage();
-	}, [imageUrl]);
-
-	return (
-		<ModalImage
-			className={classes.messageMedia}
-			smallSrcSet={fetching ? imageUrl : blobUrl}
-			medium={fetching ? imageUrl : blobUrl}
-			large={fetching ? imageUrl : blobUrl}
-			alt="image"
-		/>
-	);
-};
-
-export default ModalImageCors;

+ 0 - 263
frontend/src/components/ModalUsers/index.js

@@ -1,263 +0,0 @@
-import React, { useState, useEffect, useContext } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import Select from "@material-ui/core/Select";
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import QueueSelectCustom from "../QueueSelectCustom";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { Can } from "../Can";
-
-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,
-  },
-  formControl: {
-    margin: theme.spacing(1),
-    minWidth: 120,
-  },
-}));
-
-const UserSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, "Too Short!")
-    .max(50, "Too Long!")
-    .required("Required"),
-  password: Yup.string().min(5, "Too Short!").max(50, "Too Long!"),
-  email: Yup.string().email("Invalid email").required("Required"),
-});
-
-const ModalUsers = ({ open, onClose, userId, companyId }) => {
-  const classes = useStyles();
-
-  const initialState = {
-    name: "",
-    email: "",
-    password: "",
-    profile: "user",
-  };
-
-  const { user: loggedInUser } = useContext(AuthContext);
-
-  const [user, setUser] = useState(initialState);
-  const [selectedQueueIds, setSelectedQueueIds] = useState([]);
-
-  useEffect(() => {
-    const fetchUser = async () => {
-      if (!userId) return;
-      if (open) {
-        try {
-          const { data } = await api.get(`/users/${userId}`);
-          setUser((prevState) => {
-            return { ...prevState, ...data };
-          });
-          const userQueueIds = data.queues?.map((queue) => queue.id);
-          setSelectedQueueIds(userQueueIds);
-        } catch (err) {
-          toastError(err);
-        }
-      }
-    };
-
-    fetchUser();
-  }, [userId, open]);
-
-  const handleClose = () => {
-    onClose();
-    setUser(initialState);
-  };
-
-  const handleSaveUser = async (values) => {
-    const userData = { ...values, companyId, queueIds: selectedQueueIds };
-    try {
-      if (userId) {
-        await api.put(`/users/${userId}`, userData);
-      } else {
-        await api.post("/users", userData);
-      }
-      toast.success(i18n.t("userModal.success"));
-    } catch (err) {
-      toastError(err);
-    }
-    handleClose();
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog
-        open={open}
-        onClose={handleClose}
-        maxWidth="xs"
-        fullWidth
-        scroll="paper"
-      >
-        <DialogTitle id="form-dialog-title">
-          {userId
-            ? `${i18n.t("userModal.title.edit")}`
-            : `${i18n.t("userModal.title.add")}`}
-        </DialogTitle>
-        <Formik
-          initialValues={user}
-          enableReinitialize={true}
-          validationSchema={UserSchema}
-          onSubmit={(values, actions) => {
-            setTimeout(() => {
-              handleSaveUser(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ touched, errors, isSubmitting }) => (
-            <Form>
-              <DialogContent dividers>
-                <div className={classes.multFieldLine}>
-                  <Field
-                    as={TextField}
-                    label={i18n.t("userModal.form.name")}
-                    autoFocus
-                    name="name"
-                    error={touched.name && Boolean(errors.name)}
-                    helperText={touched.name && errors.name}
-                    variant="outlined"
-                    margin="dense"
-                    fullWidth
-                  />
-                  <Field
-                    as={TextField}
-                    label={i18n.t("userModal.form.password")}
-                    type="password"
-                    name="password"
-                    error={touched.password && Boolean(errors.password)}
-                    helperText={touched.password && errors.password}
-                    variant="outlined"
-                    margin="dense"
-                    fullWidth
-                  />
-                </div>
-                <div className={classes.multFieldLine}>
-                  <Field
-                    as={TextField}
-                    label={i18n.t("userModal.form.email")}
-                    name="email"
-                    error={touched.email && Boolean(errors.email)}
-                    helperText={touched.email && errors.email}
-                    variant="outlined"
-                    margin="dense"
-                    fullWidth
-                  />
-                  <FormControl
-                    variant="outlined"
-                    className={classes.formControl}
-                    margin="dense"
-                  >
-                    <Can
-                      role={loggedInUser.profile}
-                      perform="user-modal:editProfile"
-                      yes={() => (
-                        <>
-                          <InputLabel id="profile-selection-input-label">
-                            {i18n.t("userModal.form.profile")}
-                          </InputLabel>
-
-                          <Field
-                            as={Select}
-                            label={i18n.t("userModal.form.profile")}
-                            name="profile"
-                            labelId="profile-selection-label"
-                            id="profile-selection"
-                            required
-                          >
-                            <MenuItem value="admin">Admin</MenuItem>
-                            <MenuItem value="user">User</MenuItem>
-                          </Field>
-                        </>
-                      )}
-                    />
-                  </FormControl>
-                </div>
-                <Can
-                  role={loggedInUser.profile}
-                  perform="user-modal:editQueues"
-                  yes={() => (
-                    <QueueSelectCustom
-                      companyId={companyId}
-                      selectedQueueIds={selectedQueueIds}
-                      onChange={(values) => setSelectedQueueIds(values)}
-                    />
-                  )}
-                />
-              </DialogContent>
-              <DialogActions>
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("userModal.buttons.cancel")}
-                </Button>
-                <Button
-                  type="submit"
-                  color="primary"
-                  disabled={isSubmitting}
-                  variant="contained"
-                  className={classes.btnWrapper}
-                >
-                  {userId
-                    ? `${i18n.t("userModal.buttons.okEdit")}`
-                    : `${i18n.t("userModal.buttons.okAdd")}`}
-                  {isSubmitting && (
-                    <CircularProgress
-                      size={24}
-                      className={classes.buttonProgress}
-                    />
-                  )}
-                </Button>
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div>
-  );
-};
-
-export default ModalUsers;

+ 0 - 447
frontend/src/components/NewTicketModal/index.js

@@ -1,447 +0,0 @@
-import React, { useState, useEffect, useContext } from "react";
-
-import Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import Autocomplete, {
-	createFilterOptions,
-} from "@material-ui/lab/Autocomplete";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-import api from "../../services/api";
-import ButtonWithSpinner from "../ButtonWithSpinner";
-import ContactModal from "../ContactModal";
-import toastError from "../../errors/toastError";
-import { makeStyles } from "@material-ui/core/styles";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import {  WhatsApp } from "@material-ui/icons";
-import { Grid, ListItemText, MenuItem, Select } from "@material-ui/core";
-import Typography from "@material-ui/core/Typography";
-import { toast } from "react-toastify";
-//import ShowTicketOpen from "../ShowTicketOpenModal";
-
-const useStyles = makeStyles((theme) => ({
-  online: {
-    fontSize: 11,
-    color: "#25d366"
-  },
-  offline: {
-    fontSize: 11,
-    color: "#e1306c"
-  }
-}));
-
-const filter = createFilterOptions({
-  trim: true,
-});
-
-const NewTicketModal = ({ modalOpen, onClose, initialContact }) => {
-  const classes = useStyles();
-  const [options, setOptions] = useState([]);
-
-  const [loading, setLoading] = useState(false);
-  const [searchParam, setSearchParam] = useState("");
-  const [selectedContact, setSelectedContact] = useState(null);
-  const [selectedQueue, setSelectedQueue] = useState("");
-  const [selectedWhatsapp, setSelectedWhatsapp] = useState("");
-  const [newContact, setNewContact] = useState({});
-  const [whatsapps, setWhatsapps] = useState([]);
-  const [queues, setQueues] = useState([]);
-  const [contactModalOpen, setContactModalOpen] = useState(false);
-  const { user } = useContext(AuthContext);
-  const { companyId, whatsappId } = user;
-
-  const [ openAlert, setOpenAlert ] = useState(false);
-	const [ userTicketOpen, setUserTicketOpen] = useState("");
-	const [ queueTicketOpen, setQueueTicketOpen] = useState("");
-
-  useEffect(() => {
-    if (initialContact?.id !== undefined) {
-      setOptions([initialContact]);
-      setSelectedContact(initialContact);
-    }
-  }, [initialContact]);
-
-  useEffect(() => {
-    setLoading(true);
-    const delayDebounceFn = setTimeout(() => {
-      const fetchContacts = async () => {
-        api
-          .get(`/whatsapp`, { params: { companyId, session: 0 } })
-          .then(({ data }) => setWhatsapps(data));
-      };
-
-      if (whatsappId !== null && whatsappId!== undefined) {
-        setSelectedWhatsapp(whatsappId)
-      }
-
-      const fetchQueues = async (  ) => {
-
-        if( user.profile !== "admin" ){
-
-          setQueues( user.queues );
-          
-          if (user.queues.length === 1) {
-            setSelectedQueue(user.queues[0].id)
-          }
-
-          return;
-        }
-
-        try{
-
-          const {data: queues} = await api.get('/queue');
-          setQueues( queues )
-
-          if( queues.length === 1) {
-            setSelectedQueue(queues[0].id)
-          }
-
-        }catch(err){
-          toastError(i18n.t("newTicketModal.searchQueueError"));       
-        }        
-      }
-
-      fetchQueues(  );
-      fetchContacts(  );
-      setLoading(false);
-    }, 500);
-    return () => clearTimeout(delayDebounceFn);
-  }, [])
-
-  useEffect(() => {
-    if (!modalOpen || searchParam.length < 3) {
-      setLoading(false);
-      return;
-    }
-    setLoading(true);
-    const delayDebounceFn = setTimeout(() => {
-      const fetchContacts = async () => {
-        try {
-          const { data } = await api.get("contacts", {
-            params: { searchParam },
-          });
-          setOptions(data.contacts);
-          setLoading(false);
-        } catch (err) {
-          setLoading(false);
-          toastError(err);
-        }
-      };
-      fetchContacts();
-    }, 500);
-    return () => clearTimeout(delayDebounceFn);
-  }, [searchParam, modalOpen]);
-
-  // const IconChannel = (channel) => {
-  //   switch (channel) {
-  //     case "facebook":
-  //       return <Facebook style={{ color: "#3b5998", verticalAlign: "middle" }} />;
-  //     case "instagram":
-  //       return <Instagram style={{ color: "#e1306c", verticalAlign: "middle" }} />;
-  //     case "whatsapp":
-  //       return <WhatsApp style={{ color: "#25d366", verticalAlign: "middle" }} />
-  //     default:
-  //       return "error";
-  //   }
-  // };
-
-  const handleClose = () => {
-    onClose();
-    setSearchParam("");
-    setOpenAlert(false);
-    setUserTicketOpen("");
-    setQueueTicketOpen("");
-    setSelectedContact(null);
-  };
-
-  const handleCloseAlert = () => {
-    setOpenAlert(false);
-    setLoading(false);
-    setOpenAlert(false);
-    setUserTicketOpen("");
-    setQueueTicketOpen("");
-  };
-
-  const handleSaveTicket = async contactId => {
-    if (!contactId) return;
-    if (selectedQueue === "" && user.profile !== 'admin') {
-      toast.error(i18n.t("newTicketModal.selectQueue"));
-      return;
-    }
-    
-    setLoading(true);
-    try {
-      const queueId = selectedQueue !== "" ? selectedQueue : null;
-      const whatsappId = selectedWhatsapp !== "" ? selectedWhatsapp : null;
-      const { data: ticket } = await api.post("/tickets", {
-        contactId: contactId,
-        queueId,
-        whatsappId,
-        userId: user.id,
-        status: "open",
-      });      
-
-      onClose(ticket);
-    } catch (err) {
-      
-      console.log(err);
-      const ticket  = err.response.data.error;
-      console.log(ticket);
-
-      if( ticket === "ERR_OTHER_OPEN_TICKET" )
-        toastError(err);
-      
-      if ( ticket !== "ERR_OTHER_OPEN_TICKET" && ticket.userId !== user?.id) {
-        setOpenAlert(true);
-        setUserTicketOpen(ticket.user.name);
-        setQueueTicketOpen(ticket.queue.name);
-      } else {
-        setOpenAlert(false);
-        setUserTicketOpen("");
-        setQueueTicketOpen("");
-        setLoading(false);
-        onClose(ticket);
-      }
-    }  
-    setLoading(false);
-  };
-
-  const handleSelectOption = (e, newValue) => {
-    if (newValue?.number) {
-      setSelectedContact(newValue);
-    } else if (newValue?.name) {
-      setNewContact({ name: newValue.name });
-      setContactModalOpen(true);
-    }
-  };
-
-  const handleCloseContactModal = () => {
-    setContactModalOpen(false);    
-  };
-
-  const handleAddNewContactTicket = contact => {
-    handleSaveTicket(contact.id);
-  };
-
-  const createAddContactOption = (filterOptions, params) => {
-    const filtered = filter(filterOptions, params);
-    if (params.inputValue !== "" && !loading && searchParam.length >= 3) {
-      filtered.push({
-        name: `${params.inputValue}`,
-      });
-    }
-    return filtered;
-  };
-
-  const renderOption = option => {
-    if (option.number) {
-      return <>
-        {/* {IconChannel(option.channel)} */}
-        <Typography component="span" style={{ fontSize: 14, marginLeft: "10px", display: "inline-flex", alignItems: "center", lineHeight: "2" }}>
-          {option.name} - {option.number}
-        </Typography>
-      </>
-    } else {
-      return `${i18n.t("newTicketModal.add")} ${option.name}`;
-    }
-  };
-
-  const renderOptionLabel = option => {
-    if (option.number) {
-      return `${option.name} - ${option.number}`;
-    } else {
-      return `${option.name}`;
-    }
-  };
-
-  const renderContactAutocomplete = () => {
-    if (initialContact === undefined || initialContact.id === undefined) {
-      return (
-        <Grid xs={12} item>
-          <Autocomplete
-            fullWidth
-            options={options}
-            loading={loading}
-            clearOnBlur
-            autoHighlight
-            freeSolo
-            clearOnEscape
-            getOptionLabel={renderOptionLabel}
-            renderOption={renderOption}
-            filterOptions={createAddContactOption}
-            onChange={(e, newValue) => handleSelectOption(e, newValue)}
-            renderInput={params => (
-              <TextField
-                {...params}
-                label={i18n.t("newTicketModal.fieldLabel")}
-                variant="outlined"
-                autoFocus
-                onChange={e => setSearchParam(e.target.value)}
-                onKeyPress={e => {
-                  if (loading || !selectedContact) return;
-                  else if (e.key === "Enter") {
-                    handleSaveTicket(selectedContact.id);
-                  }
-                }}
-                InputProps={{
-                  ...params.InputProps,
-                  endAdornment: (
-                    <React.Fragment>
-                      {loading ? (
-                        <CircularProgress color="inherit" size={20} />
-                      ) : null}
-                      {params.InputProps.endAdornment}
-                    </React.Fragment>
-                  ),
-                }}
-              />
-            )}
-          />
-        </Grid>
-      )
-    }
-    return null;
-  }
-
-  return (
-    <>
-      <ContactModal
-        open={contactModalOpen}
-        initialValues={newContact}
-        onClose={handleCloseContactModal}
-        onSave={handleAddNewContactTicket}
-      ></ContactModal>
-      <Dialog open={modalOpen} onClose={handleClose}>
-        <DialogTitle id="form-dialog-title">
-          {i18n.t("newTicketModal.title")}
-        </DialogTitle>
-        <DialogContent dividers>
-          <Grid style={{ width: 300 }} container spacing={2}>
-            {/* CONTATO */}
-            {renderContactAutocomplete()}
-            {/* FILA */}
-            <Grid xs={12} item>
-              <Select
-                required
-                fullWidth
-                displayEmpty
-                variant="outlined"
-                value={selectedQueue}
-                onChange={(e) => {
-                  setSelectedQueue(e.target.value)
-                }}
-                MenuProps={{
-                  anchorOrigin: {
-                    vertical: "bottom",
-                    horizontal: "left",
-                  },
-                  transformOrigin: {
-                    vertical: "top",
-                    horizontal: "left",
-                  },
-                  getContentAnchorEl: null,
-                }}
-                renderValue={() => {
-                  if (selectedQueue === "") {
-                    return i18n.t("newTicketModal.selectQueue")
-                  }
-
-                  const queue = queues.find(q => q.id === selectedQueue)
-                  return queue.name
-                }}
-              >
-                {queues?.length > 0 &&
-                  queues.map((queue, key) => (
-                    <MenuItem dense key={key} value={queue.id}>
-                      <ListItemText primary={queue.name} />
-                    </MenuItem>
-                  ))
-                }
-              </Select>
-            </Grid>
-            {/* CONEXAO */}
-            <Grid xs={12} item>
-              <Select
-                required
-                fullWidth
-                displayEmpty
-                variant="outlined"
-                value={selectedWhatsapp}
-                onChange={(e) => {
-                  setSelectedWhatsapp(e.target.value)
-                }}
-                MenuProps={{
-                  anchorOrigin: {
-                    vertical: "bottom",
-                    horizontal: "left",
-                  },
-                  transformOrigin: {
-                    vertical: "top",
-                    horizontal: "left",
-                  },
-                  getContentAnchorEl: null,
-                }}
-                renderValue={() => {
-                  if (selectedWhatsapp === "") {
-                    return i18n.t("newTicketModal.selectConection")
-                  }
-                  const whatsapp = whatsapps.find(w => w.id === selectedWhatsapp)
-                  return whatsapp.name
-                }}
-              >
-                {whatsapps?.length > 0 &&
-                  whatsapps.map((whatsapp, key) => (
-                    <MenuItem dense key={key} value={whatsapp.id}>
-                      <ListItemText
-                        primary={
-                          <>
-                            {/* {IconChannel(whatsapp.channel)} */}
-                            <Typography component="span" style={{ fontSize: 14, marginLeft: "10px", display: "inline-flex", alignItems: "center", lineHeight: "2" }}>
-                              {whatsapp.name} &nbsp; <p className={(whatsapp.status) === 'CONNECTED' ? classes.online : classes.offline} >({whatsapp.status})</p>
-                            </Typography>
-                          </>
-                        }
-                      />
-                    </MenuItem>
-                  ))}
-              </Select>
-            </Grid>
-          </Grid>
-        </DialogContent>
-        <DialogActions>
-          <Button
-            onClick={handleClose}
-            color="secondary"
-            disabled={loading}
-            variant="outlined"
-          >
-            {i18n.t("newTicketModal.buttons.cancel")}
-          </Button>
-          <ButtonWithSpinner
-            variant="contained"
-            type="button"
-            disabled={!selectedContact}
-            onClick={() => handleSaveTicket(selectedContact.id)}
-            color="primary"
-            loading={loading}
-          >
-            {i18n.t("newTicketModal.buttons.ok")}
-          </ButtonWithSpinner>
-        </DialogActions>
-        {/* <ShowTicketOpen
-          isOpen={openAlert}
-          handleClose={handleCloseAlert}
-          user={userTicketOpen}
-          queue={queueTicketOpen}
-			  /> */}
-      </Dialog >
-    </>
-  );
-};
-export default NewTicketModal;

+ 0 - 270
frontend/src/components/NotificationsPopOver/index.js

@@ -1,270 +0,0 @@
-import React, { useState, useRef, useEffect, useContext } from "react";
-
-import { useHistory } from "react-router-dom";
-import { format } from "date-fns";
-import { SocketContext } from "../../context/Socket/SocketContext";
-
-import useSound from "use-sound";
-
-import Popover from "@material-ui/core/Popover";
-import IconButton from "@material-ui/core/IconButton";
-import List from "@material-ui/core/List";
-import ListItem from "@material-ui/core/ListItem";
-import ListItemText from "@material-ui/core/ListItemText";
-import { makeStyles } from "@material-ui/core/styles";
-import Badge from "@material-ui/core/Badge";
-import ChatIcon from "@material-ui/icons/Chat";
-
-import TicketListItem from "../TicketListItemCustom";
-import useTickets from "../../hooks/useTickets";
-import alertSound from "../../assets/sound.mp3";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { i18n } from "../../translate/i18n";
-import toastError from "../../errors/toastError";
-
-const useStyles = makeStyles(theme => ({
-	tabContainer: {
-		overflowY: "auto",
-		maxHeight: 350,
-		...theme.scrollbarStyles,
-	},
-	popoverPaper: {
-		width: "100%",
-		maxWidth: 350,
-		marginLeft: theme.spacing(2),
-		marginRight: theme.spacing(1),
-		[theme.breakpoints.down("sm")]: {
-			maxWidth: 270,
-		},
-	},
-	noShadow: {
-		boxShadow: "none !important",
-	},
-}));
-
-const NotificationsPopOver = (volume) => {
-	const classes = useStyles();
-
-	const history = useHistory();
-	const { user } = useContext(AuthContext);
-	const ticketIdUrl = +history.location.pathname.split("/")[2];
-	const ticketIdRef = useRef(ticketIdUrl);
-	const anchorEl = useRef();
-	const [isOpen, setIsOpen] = useState(false);
-	const [notifications, setNotifications] = useState([]);
-
-	const [showPendingTickets, setShowPendingTickets] = useState(false);
-
-	const [, setDesktopNotifications] = useState([]);
-
-	const { tickets } = useTickets({ withUnreadMessages: "true" });
-
-	const [play] = useSound(alertSound, volume);
-	const soundAlertRef = useRef();
-
-	const historyRef = useRef(history);
-
-  const socketManager = useContext(SocketContext);
-
-	useEffect(() => {
-		const fetchSettings = async () => {
-			try {
-
-				if (user.allTicket === "enable") {
-					setShowPendingTickets(true);
-				}
-			} catch (err) {
-			  	toastError(err);
-			}
-		}
-	  
-		fetchSettings();
-	}, []);
-
-	useEffect(() => {
-		soundAlertRef.current = play;
-
-		if (!("Notification" in window)) {
-			console.log("This browser doesn't support notifications");
-		} else {
-			Notification.requestPermission();
-		}
-	}, [play]);
-
-	useEffect(() => {
-		const processNotifications = () => {
-			if (showPendingTickets) {
-				setNotifications(tickets);
-			} else {
-				const newNotifications = tickets.filter(ticket => ticket.status !== "pending");
-
-				setNotifications(newNotifications);
-			}
-		}
-
-		processNotifications();
-	}, [tickets]);
-
-	useEffect(() => {
-		ticketIdRef.current = ticketIdUrl;
-	}, [ticketIdUrl]);
-
-	useEffect(() => {
-    const socket = socketManager.getSocket(user.companyId);
-
-		socket.on("ready", () => socket.emit("joinNotification"));
-
-		socket.on(`company-${user.companyId}-ticket`, data => {
-			if (data.action === "updateUnread" || data.action === "delete") {
-				setNotifications(prevState => {
-					const ticketIndex = prevState.findIndex(t => t.id === data.ticketId);
-					if (ticketIndex !== -1) {
-						prevState.splice(ticketIndex, 1);
-						return [...prevState];
-					}
-					return prevState;
-				});
-
-				setDesktopNotifications(prevState => {
-					const notfiticationIndex = prevState.findIndex(
-						n => n.tag === String(data.ticketId)
-					);
-					if (notfiticationIndex !== -1) {
-						prevState[notfiticationIndex].close();
-						prevState.splice(notfiticationIndex, 1);
-						return [...prevState];
-					}
-					return prevState;
-				});
-			}
-		});
-
-		socket.on(`company-${user.companyId}-appMessage`, data => {
-			if (
-				data.action === "create" && !data.message.fromMe && 
-				(data.ticket.status !== "pending" ) &&
-				(!data.message.read || data.ticket.status === "pending") &&
-				(data.ticket.userId === user?.id || !data.ticket.userId) &&
-				(user?.queues?.some(queue => (queue.id === data.ticket.queueId)) || !data.ticket.queueId)
-			) {
-				setNotifications(prevState => {
-					const ticketIndex = prevState.findIndex(t => t.id === data.ticket.id);
-					if (ticketIndex !== -1) {
-						prevState[ticketIndex] = data.ticket;
-						return [...prevState];
-					}
-					return [data.ticket, ...prevState];
-				});
-
-				const shouldNotNotificate =
-					(data.message.ticketId === ticketIdRef.current &&
-						document.visibilityState === "visible") ||
-					(data.ticket.userId && data.ticket.userId !== user?.id) ||
-					data.ticket.isGroup;
-
-				if (shouldNotNotificate) return;
-
-				handleNotifications(data);
-			}
-		});
-
-		return () => {
-			socket.disconnect();
-		};
-	}, [user, showPendingTickets, socketManager]);
-
-	const handleNotifications = data => {
-		const { message, contact, ticket } = data;
-
-		const options = {
-			body: `${message.body} - ${format(new Date(), "HH:mm")}`,
-			icon: contact.urlPicture,
-			tag: ticket.id,
-			renotify: true,
-		};
-
-		const notification = new Notification(
-			`${i18n.t("tickets.notification.message")} ${contact.name}`,
-			options
-		);
-
-		notification.onclick = e => {
-			e.preventDefault();
-			window.focus();
-			historyRef.current.push(`/tickets/${ticket.uuid}`);
-			// handleChangeTab(null, ticket.isGroup? "group" : "open");
-		};
-
-		setDesktopNotifications(prevState => {
-			const notfiticationIndex = prevState.findIndex(
-				n => n.tag === notification.tag
-			);
-			if (notfiticationIndex !== -1) {
-				prevState[notfiticationIndex] = notification;
-				return [...prevState];
-			}
-			return [notification, ...prevState];
-		});
-
-		soundAlertRef.current();
-	};
-
-	const handleClick = () => {
-		setIsOpen(prevState => !prevState);
-	};
-
-	const handleClickAway = () => {
-		setIsOpen(false);
-	};
-
-	const NotificationTicket = ({ children }) => {
-		return <div onClick={handleClickAway}>{children}</div>;
-	};
-
-	return (
-		<>
-			<IconButton
-				onClick={handleClick}
-				ref={anchorEl}
-				aria-label="Open Notifications"
-				color="inherit"
-				style={{color:"white"}}
-			>
-				<Badge overlap="rectangular" badgeContent={notifications.length} color="secondary">
-					<ChatIcon />
-				</Badge>
-			</IconButton>
-			<Popover
-				disableScrollLock
-				open={isOpen}
-				anchorEl={anchorEl.current}
-				anchorOrigin={{
-					vertical: "bottom",
-					horizontal: "right",
-				}}
-				transformOrigin={{
-					vertical: "top",
-					horizontal: "right",
-				}}
-				classes={{ paper: classes.popoverPaper }}
-				onClose={handleClickAway}
-			>
-				<List dense className={classes.tabContainer}>
-					{notifications.length === 0 ? (
-						<ListItem>
-							<ListItemText>{i18n.t("notifications.noTickets")}</ListItemText>
-						</ListItem>
-					) : (
-						notifications.map(ticket => (
-							<NotificationTicket key={ticket.id}>
-								<TicketListItem ticket={ticket} />
-							</NotificationTicket>
-						))
-					)}
-				</List>
-			</Popover>
-		</>
-	);
-};
-
-export default NotificationsPopOver;

+ 0 - 275
frontend/src/components/NotificationsPopOver/index_Antigo.js

@@ -1,275 +0,0 @@
-import React, { useState, useRef, useEffect, useContext } from "react";
-
-import { useHistory } from "react-router-dom";
-import { format } from "date-fns";
-import useSound from "use-sound";
-
-import Popover from "@material-ui/core/Popover";
-import IconButton from "@material-ui/core/IconButton";
-import List from "@material-ui/core/List";
-import ListItem from "@material-ui/core/ListItem";
-import ListItemText from "@material-ui/core/ListItemText";
-import { makeStyles } from "@material-ui/core/styles";
-import Badge from "@material-ui/core/Badge";
-import ChatIcon from "@material-ui/icons/Chat";
-
-import TicketListItem from "../TicketListItem";
-import { i18n } from "../../translate/i18n";
-import useTickets from "../../hooks/useTickets";
-import alertSound from "../../assets/sound.mp3";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { socketConnection } from "../../services/socket";
-
-const useStyles = makeStyles((theme) => ({
-  tabContainer: {
-    overflowY: "auto",
-    maxHeight: 350,
-    ...theme.scrollbarStyles,
-  },
-  popoverPaper: {
-    width: "100%",
-    maxWidth: 350,
-    marginLeft: theme.spacing(2),
-    marginRight: theme.spacing(1),
-    [theme.breakpoints.down("sm")]: {
-      maxWidth: 270,
-    },
-  },
-  noShadow: {
-    boxShadow: "none !important",
-  },
-  icons: {
-    color: "#fff",
-  },
-  customBadge: {
-    backgroundColor: "#f44336",
-    color: "#fff",
-  },
-}));
-
-const NotificationsPopOver = ({ volume }) => {
-  const classes = useStyles();
-
-  const history = useHistory();
-  const { user } = useContext(AuthContext);
-  const ticketIdUrl = +history.location.pathname.split("/")[2];
-  const ticketIdRef = useRef(ticketIdUrl);
-  const anchorEl = useRef();
-  const [isOpen, setIsOpen] = useState(false);
-  const [notifications, setNotifications] = useState([]);
-  const { profile, queues } = user;
-
-  const [, setDesktopNotifications] = useState([]);
-
-  const { tickets } = useTickets({ withUnreadMessages: "true" });
-  const [play] = useSound(alertSound, { volume, });
-  const soundAlertRef = useRef();
-
-  const historyRef = useRef(history);
-
-  useEffect(() => {
-    soundAlertRef.current = play;
-
-    if (!("Notification" in window)) {
-      console.log("This browser doesn't support notifications");
-    } else {
-      Notification.requestPermission();
-    }
-  }, [play]);
-
-  useEffect(() => {
-    const queueIds = queues.map((q) => q.id);
-    const filteredTickets = tickets.filter(
-      (t) => queueIds.indexOf(t.queueId) > -1
-    );
-
-    if (profile === "user") {
-      setNotifications(filteredTickets);
-    } else {
-      setNotifications(tickets);
-    }
-  }, [tickets, queues, profile]);
-
-  useEffect(() => {
-    ticketIdRef.current = ticketIdUrl;
-  }, [ticketIdUrl]);
-
-  useEffect(() => {
-    const companyId = localStorage.getItem("companyId");
-    const socket = socketConnection({ companyId });
-    if (!socket) {
-      return () => {}; 
-    }
-
-    const queueIds = queues.map((q) => q.id);
-
-    socket.on("connect", () => socket.emit("joinNotification"));
-
-    socket.on(`company-${companyId}-ticket`, (data) => {
-      if (data.action === "updateUnread" || data.action === "delete") {
-        setNotifications((prevState) => {
-          const ticketIndex = prevState.findIndex(
-            (t) => t.id === data.ticketId
-          );
-          if (ticketIndex !== -1) {
-            prevState.splice(ticketIndex, 1);
-            return [...prevState];
-          }
-          return prevState;
-        });
-
-        setDesktopNotifications((prevState) => {
-          const notfiticationIndex = prevState.findIndex(
-            (n) => n.tag === String(data.ticketId)
-          );
-          if (notfiticationIndex !== -1) {
-            prevState[notfiticationIndex].close();
-            prevState.splice(notfiticationIndex, 1);
-            return [...prevState];
-          }
-          return prevState;
-        });
-      }
-    });
-
-    socket.on(`company-${companyId}-appMessage`, (data) => {
-      if (
-        data.action === "create" &&
-        !data.message.read &&
-        (data.ticket.userId === user?.id || !data.ticket.userId)
-      ) {
-        if (
-          profile === "user" &&
-          (queueIds.indexOf(data.ticket.queue?.id) === -1 ||
-            data.ticket.queue === null)
-        ) {
-          return;
-        }
-
-        setNotifications((prevState) => {
-          const ticketIndex = prevState.findIndex(
-            (t) => t.id === data.ticket.id
-          );
-          if (ticketIndex !== -1) {
-            prevState[ticketIndex] = data.ticket;
-            return [...prevState];
-          }
-          return [data.ticket, ...prevState];
-        });
-
-        const shouldNotNotificate =
-          (data.message.ticketId === ticketIdRef.current &&
-            document.visibilityState === "visible") ||
-          (data.ticket.userId && data.ticket.userId !== user?.id) ||
-          data.ticket.isGroup ||
-          data.ticket.isBot;
-
-        if (shouldNotNotificate) return;
-
-        handleNotifications(data);
-      }
-    });
-
-    return () => {
-      socket.disconnect();
-    };
-  }, [user, profile, queues]);
-
-  const handleNotifications = (data) => {
-    const { message, contact, ticket } = data;
-
-    const options = {
-      body: `${message.body} - ${format(new Date(), "HH:mm")}`,
-      icon: contact.profilePicUrl,
-      tag: ticket.id,
-      renotify: true,
-    };
-
-    const notification = new Notification(
-      `${i18n.t("tickets.notification.message")} ${contact.name}`,
-      options
-    );
-
-    notification.onclick = (e) => {
-      e.preventDefault();
-      window.focus();
-      historyRef.current.push(`/tickets/${ticket.uuid}`);
-    };
-
-    setDesktopNotifications((prevState) => {
-      const notfiticationIndex = prevState.findIndex(
-        (n) => n.tag === notification.tag
-      );
-      if (notfiticationIndex !== -1) {
-        prevState[notfiticationIndex] = notification;
-        return [...prevState];
-      }
-      return [notification, ...prevState];
-    });
-
-    soundAlertRef.current();
-  };
-
-  const handleClick = () => {
-    setIsOpen((prevState) => !prevState);
-  };
-
-  const handleClickAway = () => {
-    setIsOpen(false);
-  };
-
-  const NotificationTicket = ({ children }) => {
-    return <div onClick={handleClickAway}>{children}</div>;
-  };
-
-  return (
-    <>
-      <IconButton
-        className={classes.icons}
-        onClick={handleClick}
-        ref={anchorEl}
-        aria-label="Open Notifications"
-        variant="contained"
-      >
-        <Badge
-          overlap="rectangular"
-          badgeContent={notifications.length}
-          classes={{ badge: classes.customBadge }}
-        >
-          <ChatIcon />
-        </Badge>
-      </IconButton>
-      <Popover
-        disableScrollLock
-        open={isOpen}
-        anchorEl={anchorEl.current}
-        anchorOrigin={{
-          vertical: "bottom",
-          horizontal: "right",
-        }}
-        transformOrigin={{
-          vertical: "top",
-          horizontal: "right",
-        }}
-        classes={{ paper: classes.popoverPaper }}
-        onClose={handleClickAway}
-      >
-        <List dense className={classes.tabContainer}>
-          {notifications.length === 0 ? (
-            <ListItem>
-              <ListItemText>{i18n.t("notifications.noTickets")}</ListItemText>
-            </ListItem>
-          ) : (
-            notifications.map((ticket) => (
-              <NotificationTicket key={ticket.id}>
-                <TicketListItem ticket={ticket} />
-              </NotificationTicket>
-            ))
-          )}
-        </List>
-      </Popover>
-    </>
-  );
-};
-
-export default NotificationsPopOver;

+ 0 - 110
frontend/src/components/NotificationsVolume/index.js

@@ -1,110 +0,0 @@
-import React, { useState, useRef } from "react";
-
-import Popover from "@material-ui/core/Popover";
-import IconButton from "@material-ui/core/IconButton";
-import List from "@material-ui/core/List";
-import { makeStyles } from "@material-ui/core/styles";
-import VolumeUpIcon from "@material-ui/icons/VolumeUp";
-import VolumeDownIcon from "@material-ui/icons/VolumeDown";
-
-import { Grid, Slider } from "@material-ui/core";
-
-const useStyles = makeStyles((theme) => ({
-    tabContainer: {
-        padding: theme.spacing(2),
-    },
-    popoverPaper: {
-        width: "100%",
-        maxWidth: 350,
-        marginLeft: theme.spacing(2),
-        marginRight: theme.spacing(1),
-        [theme.breakpoints.down("sm")]: {
-            maxWidth: 270,
-        },
-    },
-    noShadow: {
-        boxShadow: "none !important",
-    },
-    icons: {
-        color: "#fff",
-    },
-    customBadge: {
-        backgroundColor: "#f44336",
-        color: "#fff",
-    },
-}));
-
-const NotificationsVolume = ({ volume, setVolume }) => {
-    const classes = useStyles();
-
-    const anchorEl = useRef();
-    const [isOpen, setIsOpen] = useState(false);
-
-    const handleClick = () => {
-        setIsOpen((prevState) => !prevState);
-    };
-
-    const handleClickAway = () => {
-        setIsOpen(false);
-    };
-
-    const handleVolumeChange = (value) => {
-        setVolume(value);
-        localStorage.setItem("volume", value);
-    };
-
-    return (
-        <>
-            <IconButton
-                className={classes.icons}
-                onClick={handleClick}
-                ref={anchorEl}
-                aria-label="Open Notifications"
-                // color="inherit"
-                // color="secondary"
-            >
-                <VolumeUpIcon color="inherit" />
-            </IconButton>
-            <Popover
-                disableScrollLock
-                open={isOpen}
-                anchorEl={anchorEl.current}
-                anchorOrigin={{
-                    vertical: "bottom",
-                    horizontal: "right",
-                }}
-                transformOrigin={{
-                    vertical: "top",
-                    horizontal: "right",
-                }}
-                classes={{ paper: classes.popoverPaper }}
-                onClose={handleClickAway}
-            >
-                <List dense className={classes.tabContainer}>
-                    <Grid container spacing={2}>
-                        <Grid item>
-                            <VolumeDownIcon />
-                        </Grid>
-                        <Grid item xs>
-                            <Slider
-                                value={volume}
-                                aria-labelledby="continuous-slider"
-                                step={0.1}
-                                min={0}
-                                max={1}
-                                onChange={(e, value) =>
-                                    handleVolumeChange(value)
-                                }
-                            />
-                        </Grid>
-                        <Grid item>
-                            <VolumeUpIcon />
-                        </Grid>
-                    </Grid>
-                </List>
-            </Popover>
-        </>
-    );
-};
-
-export default NotificationsVolume;

+ 0 - 9
frontend/src/components/OnlyForSuperUser/index.js

@@ -1,9 +0,0 @@
-const OnlyForSuperUser = ({ user, yes, no }) => user.super ? yes() : no();
-
-OnlyForSuperUser.defaultProps = {
-    user: {},
-	yes: () => null,
-	no: () => null,
-};
-
-export default OnlyForSuperUser;

+ 0 - 30
frontend/src/components/OutlinedDiv/index.js

@@ -1,30 +0,0 @@
-import React from "react";
-
-import TextField from "@material-ui/core/TextField";
-
-const InputComponent = ({ inputRef, ...other }) => <div {...other} />;
-
-const OutlinedDiv = ({
-  InputProps,
-  children,
-  InputLabelProps,
-  label,
-  ...other
-}) => {
-  return (
-    <TextField
-      {...other}
-      variant="outlined"
-      label={label}
-      multiline
-      InputLabelProps={{ shrink: true, ...InputLabelProps }}
-      InputProps={{
-        inputComponent: InputComponent,
-        ...InputProps
-      }}
-      inputProps={{ children: children }}
-    />
-  );
-};
-
-export default OutlinedDiv;

+ 0 - 561
frontend/src/components/PlansManager/index.js

@@ -1,561 +0,0 @@
-import React, { useState, useEffect } from "react";
-import {
-    makeStyles,
-    Paper,
-    Grid,
-    TextField,
-    Table,
-    TableHead,
-    TableBody,
-    TableCell,
-    TableRow,
-    IconButton,
-    FormControl,
-    InputLabel,
-    MenuItem,
-    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 usePlans from "../../hooks/usePlans";
-import { i18n } from "../../translate/i18n";
-
-
-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 PlanManagerForm(props) {
-    const { onSubmit, onDelete, onCancel, initialValue, loading } = props;
-    const classes = useStyles()
-
-    const [record, setRecord] = useState({
-        name: '',
-        users: 0,
-        connections: 0,
-        queues: 0,
-        value: 0,
-        useCampaigns: true,
-        useSchedules: true,
-        useInternalChat: true,
-        useExternalApi: true,
-        useKanban: true,
-        useOpenAi: true,
-        useIntegrations: true,
-    });
-
-    useEffect(() => {
-        setRecord(initialValue)
-    }, [initialValue])
-
-    const handleSubmit = async (data) => {
-        onSubmit(data)
-    }
-
-    return (
-        <Formik
-            enableReinitialize
-            className={classes.fullWidth}
-            initialValues={record}
-            onSubmit={(values, { resetForm }) =>
-                setTimeout(() => {
-                    handleSubmit(values)
-                    resetForm()
-                }, 500)
-            }
-        >
-            {(values) => (
-                <Form className={classes.fullWidth}>
-                    <Grid spacing={1} justifyContent="flex-start" container>
-                        {/* NOME */}
-                        <Grid xs={12} sm={6} md={2} item>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("plans.form.name")}
-                                name="name"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                            />
-                        </Grid>
-
-                        {/* USUARIOS */}
-                        <Grid xs={12} sm={6} md={1} item>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("plans.form.users")}
-                                name="users"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                                type="number"
-                            />
-                        </Grid>
-
-                        {/* CONEXOES */}
-                        <Grid xs={12} sm={6} md={1} item>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("plans.form.connections")}
-                                name="connections"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                                type="number"
-                            />
-                        </Grid>
-
-                        {/* FILAS */}
-                        <Grid xs={12} sm={6} md={1} item>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("plans.form.queues")}
-                                name="queues"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                                type="number"
-                            />
-                        </Grid>
-
-                        {/* VALOR */}
-                        <Grid xs={12} sm={6} md={1} item>
-                            <Field
-                                as={TextField}
-                                label={i18n.t("plans.form.value")}
-                                name="value"
-                                variant="outlined"
-                                className={classes.fullWidth}
-                                margin="dense"
-                                type="text"
-                            />
-                        </Grid>
-
-                        {/* CAMPANHAS */}
-                        <Grid xs={12} sm={6} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useCampaigns-selection">{i18n.t("plans.form.campaigns")}</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useCampaigns-selection"
-                                    label={i18n.t("plans.form.campaigns")}
-                                    labelId="useCampaigns-selection-label"
-                                    name="useCampaigns"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* AGENDAMENTOS */}
-                        <Grid xs={12} sm={8} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useSchedules-selection">{i18n.t("plans.form.schedules")}</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useSchedules-selection"
-                                    label={i18n.t("plans.form.schedules")}
-                                    labelId="useSchedules-selection-label"
-                                    name="useSchedules"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* CHAT INTERNO */}
-                        <Grid xs={12} sm={8} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useInternalChat-selection">{i18n.t("plans.form.internalChat")}</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useInternalChat-selection"
-                                    label={i18n.t("plans.form.internalChat")}
-                                    labelId="useInternalChat-selection-label"
-                                    name="useInternalChat"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* API Externa */}
-                        <Grid xs={12} sm={8} md={4} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useExternalApi-selection">{i18n.t("plans.form.externalApi")}</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useExternalApi-selection"
-                                    label={i18n.t("plans.form.externalApi")}
-                                    labelId="useExternalApi-selection-label"
-                                    name="useExternalApi"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* KANBAN */}
-                        <Grid xs={12} sm={8} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useKanban-selection">{i18n.t("plans.form.kanban")}</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useKanban-selection"
-                                    label={i18n.t("plans.form.kanban")}
-                                    labelId="useKanban-selection-label"
-                                    name="useKanban"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* OPENAI */}
-                        <Grid xs={12} sm={8} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useOpenAi-selection">Open.Ai</InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useOpenAi-selection"
-                                    label="Talk.Ai"
-                                    labelId="useOpenAi-selection-label"
-                                    name="useOpenAi"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-
-                        {/* INTEGRACOES */}
-                        <Grid xs={12} sm={8} md={2} item>
-                            <FormControl margin="dense" variant="outlined" fullWidth>
-                                <InputLabel htmlFor="useIntegrations-selection">
-                                    {i18n.t("plans.form.integrations")}
-                                </InputLabel>
-                                <Field
-                                    as={Select}
-                                    id="useIntegrations-selection"
-                                    label={i18n.t("plans.form.integrations")}
-                                    labelId="useIntegrations-selection-label"
-                                    name="useIntegrations"
-                                    margin="dense"
-                                >
-                                    <MenuItem value={true}>{i18n.t("plans.form.enabled")}</MenuItem>
-                                    <MenuItem value={false}>{i18n.t("plans.form.disabled")}</MenuItem>
-                                </Field>
-                            </FormControl>
-                        </Grid>
-                    </Grid>
-                    <Grid spacing={2} justifyContent="flex-end" container>
-
-                        <Grid sm={3} md={2} item>
-                            <ButtonWithSpinner className={classes.fullWidth} loading={loading} onClick={() => onCancel()} variant="contained">
-                                {i18n.t("plans.form.clear")}
-                            </ButtonWithSpinner>
-                        </Grid>
-                        {record.id !== undefined ? (
-                            <Grid sm={3} md={2} item>
-                                <ButtonWithSpinner className={classes.fullWidth} loading={loading} onClick={() => onDelete(record)} variant="contained" color="secondary">
-                                    {i18n.t("plans.form.delete")}
-                                </ButtonWithSpinner>
-                            </Grid>
-                        ) : null}
-                        <Grid sm={3} md={2} item>
-                            <ButtonWithSpinner className={classes.fullWidth} loading={loading} type="submit" variant="contained" color="primary">
-                                {i18n.t("plans.form.save")}
-                            </ButtonWithSpinner>
-                        </Grid>
-                    </Grid>
-                </Form>
-            )}
-        </Formik>
-    )
-}
-
-export function PlansManagerGrid(props) {
-    const { records, onSelect } = props
-    const classes = useStyles()
-    
-    const renderCampaigns = (row) => {
-        return row.useCampaigns === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderSchedules = (row) => {
-        return row.useSchedules === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderInternalChat = (row) => {
-        return row.useInternalChat === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderExternalApi = (row) => {
-        return row.useExternalApi === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderKanban = (row) => {
-        return row.useKanban === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderOpenAi = (row) => {
-        return row.useOpenAi === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    const renderIntegrations = (row) => {
-        return row.useIntegrations === false ? `${i18n.t("plans.form.no")}` : `${i18n.t("plans.form.yes")}`;
-    };
-
-    return (
-        <Paper className={classes.tableContainer}>
-            <Table
-                className={classes.fullWidth}
-                // size="small"
-                padding="none"
-                aria-label="a dense table"
-            >
-                <TableHead>
-                    <TableRow>
-                        <TableCell align="center" style={{ width: '1%' }}>#</TableCell>
-                        <TableCell align="left">{i18n.t("plans.form.name")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.users")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.connections")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.queues")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.value")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.campaigns")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.schedules")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.internalChat")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.externalApi")}</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.kanban")}</TableCell>
-                        <TableCell align="center">Open.Ai</TableCell>
-                        <TableCell align="center">{i18n.t("plans.form.integrations")}</TableCell>
-                    </TableRow>
-                </TableHead>
-                <TableBody>
-                    {records.map((row) => (
-                        <TableRow key={row.id}>
-                            <TableCell align="center" style={{ width: '1%' }}>
-                                <IconButton onClick={() => onSelect(row)} aria-label="delete">
-                                    <EditIcon />
-                                </IconButton>
-                            </TableCell>
-                            <TableCell align="left">{row.name || '-'}</TableCell>
-                            <TableCell align="center">{row.users || '-'}</TableCell>
-                            <TableCell align="center">{row.connections || '-'}</TableCell>
-                            <TableCell align="center">{row.queues || '-'}</TableCell>
-                            <TableCell align="center">{i18n.t("plans.form.money")} {row.value ? row.value.toLocaleString('pt-br', { minimumFractionDigits: 2 }) : '00.00'}</TableCell>
-                            <TableCell align="center">{renderCampaigns(row)}</TableCell>
-                            <TableCell align="center">{renderSchedules(row)}</TableCell>
-                            <TableCell align="center">{renderInternalChat(row)}</TableCell>
-                            <TableCell align="center">{renderExternalApi(row)}</TableCell>
-                            <TableCell align="center">{renderKanban(row)}</TableCell>
-                            <TableCell align="center">{renderOpenAi(row)}</TableCell>
-                            <TableCell align="center">{renderIntegrations(row)}</TableCell>
-                        </TableRow>
-                    ))}
-                </TableBody>
-            </Table>
-        </Paper>
-    )
-}
-
-export default function PlansManager() {
-    const classes = useStyles()
-    const { list, save, update, remove } = usePlans()
-
-    const [showConfirmDialog, setShowConfirmDialog] = useState(false)
-    const [loading, setLoading] = useState(false)
-    const [records, setRecords] = useState([])
-    const [record, setRecord] = useState({
-        name: '',
-        users: 0,
-        connections: 0,
-        queues: 0,
-        value: 0,
-        useCampaigns: true,
-        useSchedules: true,
-        useInternalChat: true,
-        useExternalApi: true,
-        useKanban: true,
-        useOpenAi: true,
-        useIntegrations: true,
-    })
-
-    useEffect(() => {
-        async function fetchData() {
-            await loadPlans()
-        }
-        fetchData()
-        // eslint-disable-next-line react-hooks/exhaustive-deps
-    }, [record])
-
-    const loadPlans = async () => {
-        setLoading(true)
-        try {
-            const planList = await list()
-            setRecords(planList)
-        } catch (e) {
-            toast.error(i18n.t("plans.toasts.errorList"))
-        }
-        setLoading(false)
-    }
-
-    const handleSubmit = async (data) => {
-        setLoading(true)
-        console.log(data)
-        try {
-            if (data.id !== undefined) {
-                await update(data)
-            } else {
-                await save(data)
-            }
-            await loadPlans()
-            handleCancel()
-            toast.success(i18n.t("plans.toasts.success"))
-        } catch (e) {
-            toast.error(i18n.t("plans.toasts.error"))
-        }
-        setLoading(false)
-    }
-
-    const handleDelete = async () => {
-        setLoading(true)
-        try {
-            await remove(record.id)
-            await loadPlans()
-            handleCancel()
-            toast.success(i18n.t("plans.toasts.success"))
-        } catch (e) {
-            toast.error(i18n.t("plans.toasts.errorOperation"))
-        }
-        setLoading(false)
-    }
-
-    const handleOpenDeleteDialog = () => {
-        setShowConfirmDialog(true)
-    }
-
-    const handleCancel = () => {
-        setRecord({
-            id: undefined,
-            name: '',
-            users: 0,
-            connections: 0,
-            queues: 0,
-            value: 0,
-            useCampaigns: true,
-            useSchedules: true,
-            useInternalChat: true,
-            useExternalApi: true,
-            useKanban: true,
-            useOpenAi: true,
-            useIntegrations: true
-        })
-    }
-
-    const handleSelect = (data) => {
-
-        let useCampaigns = data.useCampaigns === false ? false : true
-        let useSchedules = data.useSchedules === false ? false : true
-        let useInternalChat = data.useInternalChat === false ? false : true
-        let useExternalApi = data.useExternalApi === false ? false : true
-        let useKanban = data.useKanban === false ? false : true
-        let useOpenAi = data.useOpenAi === false ? false : true
-        let useIntegrations = data.useIntegrations === false ? false : true
-
-        setRecord({
-            id: data.id,
-            name: data.name || '',
-            users: data.users || 0,
-            connections: data.connections || 0,
-            queues: data.queues || 0,
-            value: data.value?.toLocaleString('pt-br', { minimumFractionDigits: 0 }) || 0,
-            useCampaigns,
-            useSchedules,
-            useInternalChat,
-            useExternalApi,
-            useKanban,
-            useOpenAi,
-            useIntegrations
-        })
-    }
-
-    return (
-        <Paper className={classes.mainPaper} elevation={0}>
-            <Grid spacing={2} container>
-                <Grid xs={12} item>
-                    <PlanManagerForm
-                        initialValue={record}
-                        onDelete={handleOpenDeleteDialog}
-                        onSubmit={handleSubmit}
-                        onCancel={handleCancel}
-                        loading={loading}
-                    />
-                </Grid>
-                <Grid xs={12} item>
-                    <PlansManagerGrid
-                        records={records}
-                        onSelect={handleSelect}
-                    />
-                </Grid>
-            </Grid>
-            <ConfirmationModal
-                title={i18n.t("plans.confirm.title")}
-                open={showConfirmDialog}
-                onClose={() => setShowConfirmDialog(false)}
-                onConfirm={() => handleDelete()}
-            >
-                {i18n.t("plans.confirm.message")}
-            </ConfirmationModal>
-        </Paper>
-    )
-}

+ 0 - 312
frontend/src/components/PromptModal/index.js

@@ -1,312 +0,0 @@
-import React, { useState, useEffect } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import { i18n } from "../../translate/i18n";
-import { MenuItem, FormControl, InputLabel, Select, Menu, Grid } from "@material-ui/core";
-import { Visibility, VisibilityOff } from "@material-ui/icons";
-import { InputAdornment, IconButton } from "@material-ui/core";
-import QueueSelectSingle from "../../components/QueueSelectSingle";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-
-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,
-    },
-    formControl: {
-        margin: theme.spacing(1),
-        minWidth: 120,
-    },
-    colorAdorment: {
-        width: 20,
-        height: 20,
-    },
-}));
-
-const PromptSchema = Yup.object().shape({
-    name: Yup.string().min(5, i18n.t("promptModal.formErrors.name.short")).max(100, i18n.t("promptModal.formErrors.name.long")).required(i18n.t("promptModal.formErrors.name.required")),
-    prompt: Yup.string().min(50, i18n.t("promptModal.formErrors.prompt.short")).required(i18n.t("promptModal.formErrors.prompt.required")),
-    model: Yup.string().required(i18n.t("promptModal.formErrors.modal.required")),
-    maxTokens: Yup.number().required(i18n.t("promptModal.formErrors.maxTokens.required")),
-    temperature: Yup.number().required(i18n.t("promptModal.formErrors.temperature.required")),
-    apiKey: Yup.string().required(i18n.t("promptModal.formErrors.apikey.required")),
-    queueId: Yup.number().required(i18n.t("promptModal.formErrors.queueId.required")),
-    maxMessages: Yup.number().required(i18n.t("promptModal.formErrors.maxMessages.required"))
-});
-
-const PromptModal = ({ open, onClose, promptId, refreshPrompts }) => {
-    const classes = useStyles();
-    const [selectedModel, setSelectedModel] = useState("gpt-3.5-turbo-1106");
-    const [showApiKey, setShowApiKey] = useState(false);
-
-    const handleToggleApiKey = () => {
-        setShowApiKey(!showApiKey);
-    };
-
-    const initialState = {
-        name: "",
-        prompt: "",
-        model: "gpt-3.5-turbo-1106",
-        maxTokens: 100,
-        temperature: 1,
-        apiKey: "",
-        queueId: '',
-        maxMessages: 10
-    };
-
-    const [prompt, setPrompt] = useState(initialState);
-
-    useEffect(() => {
-        const fetchPrompt = async () => {
-            if (!promptId) {
-                setPrompt(initialState);
-                return;
-            }
-            try {
-                const { data } = await api.get(`/prompt/${promptId}`);
-                setPrompt(prevState => {
-                    return { ...prevState, ...data };
-                });
-                
-                setSelectedModel(data.model);
-            } catch (err) { 
-                toastError(err);
-            }
-        };
-
-        fetchPrompt();
-    }, [promptId, open]);
-
-    const handleClose = () => {
-        setPrompt(initialState);
-        setSelectedModel("gpt-3.5-turbo-1106");
-        onClose();
-    };
-
-    const handleChangeModel = (e) => {
-        setSelectedModel(e.target.value);
-    };
-
-    const handleSavePrompt = async values => {
-        const promptData = { ...values, model: selectedModel };
-        console.log(promptData);
-        if (!values.queueId) {
-            toastError(i18n.t("promptModal.setor"));
-            return;
-        }
-        try {
-            if (promptId) {
-                await api.put(`/prompt/${promptId}`, promptData);
-            } else {
-                await api.post("/prompt", promptData);
-            }
-            toast.success(i18n.t("promptModal.success"));
-            refreshPrompts(  )
-        } catch (err) {
-            toastError(err);
-        }
-        handleClose();
-    };
-
-    return (
-        <div className={classes.root}>
-            <Dialog
-                open={open}
-                onClose={handleClose}
-                maxWidth="md"
-                scroll="paper"
-                fullWidth
-            >
-                <DialogTitle id="form-dialog-title">
-                    {promptId
-                        ? `${i18n.t("promptModal.title.edit")}`
-                        : `${i18n.t("promptModal.title.add")}`}
-                </DialogTitle>
-                <Formik
-                    initialValues={prompt}
-                    enableReinitialize={true}
-                    validationSchema={PromptSchema}
-                    onSubmit={(values, actions) => {
-                        setTimeout(() => {
-                            handleSavePrompt(values);
-                            actions.setSubmitting(false);
-                        }, 400);
-                    }}
-                >
-                    {({ touched, errors, isSubmitting, values }) => (
-                        <Form style={{ width: "100%" }}>
-                            <DialogContent dividers>
-                                <Field
-                                    as={TextField}
-                                    label={i18n.t("promptModal.form.name")}
-                                    name="name"
-                                    error={touched.name && Boolean(errors.name)}
-                                    helperText={touched.name && errors.name}
-                                    variant="outlined"
-                                    margin="dense"
-                                    fullWidth
-                                />
-                                <FormControl fullWidth margin="dense" variant="outlined">
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("promptModal.form.apikey")}
-                                        name="apiKey"
-                                        type={showApiKey ? 'text' : 'password'}
-                                        error={touched.apiKey && Boolean(errors.apiKey)}
-                                        helperText={touched.apiKey && errors.apiKey}
-                                        variant="outlined"
-                                        margin="dense"
-                                        fullWidth
-                                        InputProps={{
-                                            endAdornment: (
-                                                <InputAdornment position="end">
-                                                    <IconButton onClick={handleToggleApiKey}>
-                                                        {showApiKey ? <VisibilityOff /> : <Visibility />}
-                                                    </IconButton>
-                                                </InputAdornment>
-                                            ),
-                                        }}
-                                    />
-                                </FormControl>
-                                <Field
-                                    as={TextField}
-                                    label={i18n.t("promptModal.form.prompt")}
-                                    name="prompt"
-                                    error={touched.prompt && Boolean(errors.prompt)}
-                                    helperText={touched.prompt && errors.prompt}
-                                    variant="outlined"
-                                    margin="dense"
-                                    fullWidth
-                                    rows={10}
-                                    multiline={true}
-                                />
-                                <QueueSelectSingle touched={touched} errors={errors}/>
-                                <div className={classes.multFieldLine}>
-                                    <FormControl fullWidth margin="dense" variant="outlined">
-                                    <InputLabel>{i18n.t("promptModal.form.model")}</InputLabel>
-                                        <Select
-                                            id="type-select"
-                                            labelWidth={60}
-                                            name="model"
-                                            value={selectedModel}
-                                            onChange={handleChangeModel}
-                                            multiple={false}
-                                        >
-                                            <MenuItem key={"gpt-3.5"} value={"gpt-3.5-turbo-1106"}>
-                                                GPT 3.5 turbo
-                                            </MenuItem>
-                                            <MenuItem key={"gpt-4"} value={"gpt-4o-mini"}>
-                                                GPT 4.0
-                                            </MenuItem>
-                                        </Select>
-                                    </FormControl>
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("promptModal.form.temperature")}
-                                        name="temperature"
-                                        error={touched.temperature && Boolean(errors.temperature)}
-                                        helperText={touched.temperature && errors.temperature}
-                                        variant="outlined"
-                                        margin="dense"
-                                        fullWidth
-                                        type="number"
-                                        inputProps={{
-                                            step: "0.1",
-                                            min: "0",
-                                            max: "1"
-                                        }}
-                                    />
-                                </div>
-                                
-                                <div className={classes.multFieldLine}>
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("promptModal.form.max_tokens")}
-                                        name="maxTokens"
-                                        error={touched.maxTokens && Boolean(errors.maxTokens)}
-                                        helperText={touched.maxTokens && errors.maxTokens}
-                                        variant="outlined"
-                                        margin="dense"
-                                        fullWidth
-                                    />
-                                    <Field
-                                        as={TextField}
-                                        label={i18n.t("promptModal.form.max_messages")}
-                                        name="maxMessages"
-                                        error={touched.maxMessages && Boolean(errors.maxMessages)}
-                                        helperText={touched.maxMessages && errors.maxMessages}
-                                        variant="outlined"
-                                        margin="dense"
-                                        fullWidth
-                                    />
-                                </div>
-                            </DialogContent>
-                            <DialogActions>
-                                <Button
-                                    onClick={handleClose}
-                                    color="secondary"
-                                    disabled={isSubmitting}
-                                    variant="outlined"
-                                >
-                                    {i18n.t("promptModal.buttons.cancel")}
-                                </Button>
-                                <Button
-                                    type="submit"
-                                    color="primary"
-                                    disabled={isSubmitting}
-                                    variant="contained"
-                                    className={classes.btnWrapper}
-                                >
-                                    {promptId
-                                        ? `${i18n.t("promptModal.buttons.okEdit")}`
-                                        : `${i18n.t("promptModal.buttons.okAdd")}`}
-                                    {isSubmitting && (
-                                        <CircularProgress
-                                            size={24}
-                                            className={classes.buttonProgress}
-                                        />
-                                    )}
-                                </Button>
-                            </DialogActions>
-                        </Form>
-                    )}
-                </Formik>
-            </Dialog>
-        </div>
-    );
-};
-
-export default PromptModal;

+ 0 - 84
frontend/src/components/QrcodeModal/index.js

@@ -1,84 +0,0 @@
-import React, { useEffect, useState, useContext } from "react";
-import QRCode from "qrcode.react";
-import toastError from "../../errors/toastError";
-
-import { Dialog, DialogContent, Paper, Typography, useTheme } from "@material-ui/core";
-import { i18n } from "../../translate/i18n";
-import api from "../../services/api";
-import { SocketContext } from "../../context/Socket/SocketContext";
-
-const QrcodeModal = ({ open, onClose, whatsAppId }) => {
-  const [qrCode, setQrCode] = useState("");
-  const theme = useTheme();
-
-  const socketManager = useContext(SocketContext);
-
-  useEffect(() => {
-    const fetchSession = async () => {
-      if (!whatsAppId) return;
-
-      try {
-        const { data } = await api.get(`/whatsapp/${whatsAppId}`);
-        setQrCode(data.qrcode);
-      } catch (err) {
-        toastError(err);
-      }
-    };
-    fetchSession();
-  }, [whatsAppId]);
-
-  useEffect(() => {
-    if (!whatsAppId) return;
-    const companyId = localStorage.getItem("companyId");
-    const socket = socketManager.getSocket(companyId);
-
-    socket.on(`company-${companyId}-whatsappSession`, (data) => {
-      if (data.action === "update" && data.session.id === whatsAppId) {
-        setQrCode(data.session.qrcode);
-      }
-
-      if (data.action === "update" && data.session.qrcode === "") {
-        onClose();
-      }
-    });
-
-    return () => {
-      socket.disconnect();
-    };
-  }, [whatsAppId, onClose, socketManager]);
-
-  return (
-    <Dialog open={open} onClose={onClose} maxWidth="lg" scroll="paper">
-      <DialogContent>
-        <Paper elevation={0} style={{ display: "flex", alignItems: "center" }}>
-          <div style={{ marginRight: "20px" }}>
-            <Typography variant="h2" component="h2" color="textPrimary" gutterBottom style={{ fontFamily: "Montserrat", fontWeight: "bold", fontSize:"20px",}}>
-              {i18n.t("qrCodeModal.title")}
-            </Typography>
-            <Typography variant="body1" color="textPrimary" gutterBottom>
-              {i18n.t("qrCodeModal.steps.one")}
-            </Typography>
-            <Typography variant="body1" color="textPrimary" gutterBottom>
-              {i18n.t("qrCodeModal.steps.two.partOne")} <svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"></path></svg> {i18n.t("qrCodeModal.steps.two.partTwo")} <svg class="MuiSvgIcon-root" focusable="false" viewBox="0 0 24 24" aria-hidden="true"><path d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"></path></svg> {i18n.t("qrCodeModal.steps.two.partThree")}
-            </Typography>
-            <Typography variant="body1" color="textPrimary" gutterBottom>
-              {i18n.t("qrCodeModal.steps.three")}
-            </Typography>
-            <Typography variant="body1" color="textPrimary" gutterBottom>
-              {i18n.t("qrCodeModal.steps.four")}
-            </Typography>
-          </div>
-          <div>
-            {qrCode ? (
-              <QRCode value={qrCode} size={256} />
-            ) : (
-              <span>{i18n.t("qrCodeModal.waiting")}</span>
-            )}
-          </div>
-        </Paper>
-      </DialogContent>
-    </Dialog>
-  );
-};
-
-export default React.memo(QrcodeModal);

+ 0 - 505
frontend/src/components/QueueIntegrationModal/index.js

@@ -1,505 +0,0 @@
-import React, { useState, useEffect } from "react";
-
-import * as Yup from "yup";
-import { Formik, Form, Field } from "formik";
-import { toast } from "react-toastify";
-
-import {
-  Button,
-  Dialog,
-  DialogActions,
-  DialogContent,
-  DialogTitle,
-  CircularProgress,
-  Select,
-  InputLabel,
-  MenuItem,
-  FormControl,
-  TextField,
-  Grid,
-  Paper,
-} from "@material-ui/core";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: "flex",
-    flexWrap: "wrap",
-    gap: 4
-  },
-  textField: {
-    marginRight: theme.spacing(1),
-    flex: 1,
-  },
-
-  btnWrapper: {
-    position: "relative",
-  },
-
-  buttonProgress: {
-    color: green[500],
-    position: "absolute",
-    top: "50%",
-    left: "50%",
-    marginTop: -12,
-    marginLeft: -12,
-  },
-  btnLeft: {
-    display: "flex",
-    marginRight: "auto",
-    marginLeft: 12,
-  },
-  colorAdorment: {
-    width: 20,
-    height: 20,
-  },
-}));
-
-const DialogflowSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, "Too Short!")
-    .max(50, "Too Long!")
-    .required("Required"),
-  // projectName: Yup.string()
-  //   .min(3, "Too Short!")
-  //   .max(100, "Too Long!")
-  //   .required(),
-  // jsonContent: Yup.string().min(3, "Too Short!").required(),
-  // language: Yup.string().min(2, "Too Short!").max(50, "Too Long!").required(),
-});
-
-
-
-const QueueIntegration = ({ open, onClose, integrationId }) => {
-  const classes = useStyles();
-
-  const initialState = {
-    type: "typebot",
-    name: "",
-    projectName: "",
-    jsonContent: "",
-    language: "",
-    urlN8N: "",
-    typebotDelayMessage: 1000,
-    typebotExpires: 1,
-    typebotKeywordFinish: "",
-    typebotKeywordRestart: "",
-    typebotRestartMessage: "",
-    typebotSlug: "",
-    typebotUnknownMessage: "",
-
-  };
-
-  const [integration, setIntegration] = useState(initialState);
-
-  useEffect(() => {
-    (async () => {
-      if (!integrationId) return;
-      try {
-        const { data } = await api.get(`/queueIntegration/${integrationId}`);
-        setIntegration((prevState) => {
-          return { ...prevState, ...data };
-        });
-      } catch (err) {
-        toastError(err);
-      }
-    })();
-
-    return () => {
-      setIntegration({
-        type: "dialogflow",
-        name: "",
-        projectName: "",
-        jsonContent: "",
-        language: "",
-        urlN8N: "",
-        typebotDelayMessage: 1000
-      });
-    };
-
-  }, [integrationId, open]);
-
-  const handleClose = () => {
-    onClose();
-    setIntegration(initialState);
-  };
-
-  const handleTestSession = async (event, values) => {
-    try {
-      const { projectName, jsonContent, language } = values;
-
-      await api.post(`/queueIntegration/testSession`, {
-        projectName,
-        jsonContent,
-        language,
-      });
-
-      toast.success(i18n.t("queueIntegrationModal.messages.testSuccess"));
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  const handleSaveDialogflow = async (values) => {
-    try {
-      if (values.type === 'n8n' || values.type === 'webhook' || values.type === 'typebot') values.projectName = values.name
-      if (integrationId) {
-        await api.put(`/queueIntegration/${integrationId}`, values);
-        toast.success(i18n.t("queueIntegrationModal.messages.editSuccess"));
-      } else {
-        await api.post("/queueIntegration", values);
-        toast.success(i18n.t("queueIntegrationModal.messages.addSuccess"));
-      }
-      handleClose();
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog open={open} onClose={handleClose} fullWidth maxWidth="md" scroll="paper">
-        <DialogTitle>
-          {integrationId
-            ? `${i18n.t("queueIntegrationModal.title.edit")}`
-            : `${i18n.t("queueIntegrationModal.title.add")}`}
-        </DialogTitle>
-        <Formik
-          initialValues={integration}
-          enableReinitialize={true}
-          validationSchema={DialogflowSchema}
-          onSubmit={(values, actions, event) => {
-            setTimeout(() => {
-              handleSaveDialogflow(values);
-              actions.setSubmitting(false);
-            }, 400);
-          }}
-        >
-          {({ touched, errors, isSubmitting, values }) => (
-            <Form>
-              <Paper square className={classes.mainPaper} elevation={1}>
-                <DialogContent dividers>
-                  <Grid container spacing={1}>
-                    <Grid item xs={12} md={6} xl={6}>
-                      <FormControl
-                        variant="outlined"
-                        className={classes.formControl}
-                        margin="dense"
-                        fullWidth
-                      >
-                        <InputLabel id="type-selection-input-label">
-                          {i18n.t("queueIntegrationModal.form.type")}
-                        </InputLabel>
-
-                        <Field
-                          as={Select}
-                          label={i18n.t("queueIntegrationModal.form.type")}
-                          name="type"
-                          labelId="profile-selection-label"
-                          error={touched.type && Boolean(errors.type)}
-                          helpertext={touched.type && errors.type}
-                          id="type"
-                          required
-                        >
-                          <MenuItem value="dialogflow">DialogFlow</MenuItem>
-                          <MenuItem value="n8n">N8N</MenuItem>
-                          <MenuItem value="webhook">WebHooks</MenuItem>
-                          <MenuItem value="typebot">Typebot</MenuItem>
-                        </Field>
-                      </FormControl>
-                    </Grid>
-                    {values.type === "dialogflow" && (
-                      <>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.name")}
-                            autoFocus
-                            name="name"
-                            fullWidth
-                            error={touched.name && Boolean(errors.name)}
-                            helpertext={touched.name && errors.name}
-                            variant="outlined"
-                            margin="dense"
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <FormControl
-                            variant="outlined"
-                            className={classes.formControl}
-                            margin="dense"
-                            fullWidth
-                          >
-                            <InputLabel id="language-selection-input-label">
-                              {i18n.t("queueIntegrationModal.form.language")}
-                            </InputLabel>
-
-                            <Field
-                              as={Select}
-                              label={i18n.t("queueIntegrationModal.form.language")}
-                              name="language"
-                              labelId="profile-selection-label"
-                              fullWidth
-                              error={touched.language && Boolean(errors.language)}
-                              helpertext={touched.language && errors.language}
-                              id="language-selection"
-                              required
-                            >
-                              <MenuItem value="pt-BR">Portugues</MenuItem>
-                              <MenuItem value="en">Inglês</MenuItem>
-                              <MenuItem value="es">Español</MenuItem>
-                            </Field>
-                          </FormControl>
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.projectName")}
-                            name="projectName"
-                            error={touched.projectName && Boolean(errors.projectName)}
-                            helpertext={touched.projectName && errors.projectName}
-                            fullWidth
-                            variant="outlined"
-                            margin="dense"
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={12} xl={12} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.jsonContent")}
-                            type="jsonContent"
-                            multiline
-                            //inputRef={greetingRef}
-                            maxRows={5}
-                            minRows={5}
-                            fullWidth
-                            name="jsonContent"
-                            error={touched.jsonContent && Boolean(errors.jsonContent)}
-                            helpertext={touched.jsonContent && errors.jsonContent}
-                            variant="outlined"
-                            margin="dense"
-                          />
-                        </Grid>
-                      </>
-                    )}
-
-                    {(values.type === "n8n" || values.type === "webhook") && (
-                      <>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.name")}
-                            autoFocus
-                            required
-                            name="name"
-                            error={touched.name && Boolean(errors.name)}
-                            helpertext={touched.name && errors.name}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={12} xl={12} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.urlN8N")}
-                            name="urlN8N"
-                            error={touched.urlN8N && Boolean(errors.urlN8N)}
-                            helpertext={touched.urlN8N && errors.urlN8N}
-                            variant="outlined"
-                            margin="dense"
-                            required
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                      </>
-                    )}
-                    {(values.type === "typebot") && (
-                      <>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.name")}
-                            autoFocus
-                            name="name"
-                            error={touched.name && Boolean(errors.name)}
-                            helpertext={touched.name && errors.name}
-                            variant="outlined"
-                            margin="dense"
-                            required
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={12} xl={12} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.urlN8N")}
-                            name="urlN8N"
-                            error={touched.urlN8N && Boolean(errors.urlN8N)}
-                            helpertext={touched.urlN8N && errors.urlN8N}
-                            variant="outlined"
-                            margin="dense"
-                            required
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotSlug")}
-                            name="typebotSlug"
-                            error={touched.typebotSlug && Boolean(errors.typebotSlug)}
-                            helpertext={touched.typebotSlug && errors.typebotSlug}
-                            required
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotExpires")}
-                            name="typebotExpires"
-                            error={touched.typebotExpires && Boolean(errors.typebotExpires)}
-                            helpertext={touched.typebotExpires && errors.typebotExpires}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotDelayMessage")}
-                            name="typebotDelayMessage"
-                            error={touched.typebotDelayMessage && Boolean(errors.typebotDelayMessage)}
-                            helpertext={touched.typebotDelayMessage && errors.typebotDelayMessage}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotKeywordFinish")}
-                            name="typebotKeywordFinish"
-                            error={touched.typebotKeywordFinish && Boolean(errors.typebotKeywordFinish)}
-                            helpertext={touched.typebotKeywordFinish && errors.typebotKeywordFinish}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotKeywordRestart")}
-                            name="typebotKeywordRestart"
-                            error={touched.typebotKeywordRestart && Boolean(errors.typebotKeywordRestart)}
-                            helpertext={touched.typebotKeywordRestart && errors.typebotKeywordRestart}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={6} xl={6} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotUnknownMessage")}
-                            name="typebotUnknownMessage"
-                            error={touched.typebotUnknownMessage && Boolean(errors.typebotUnknownMessage)}
-                            helpertext={touched.typebotUnknownMessage && errors.typebotUnknownMessage}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        <Grid item xs={12} md={12} xl={12} >
-                          <Field
-                            as={TextField}
-                            label={i18n.t("queueIntegrationModal.form.typebotRestartMessage")}
-                            name="typebotRestartMessage"
-                            error={touched.typebotRestartMessage && Boolean(errors.typebotRestartMessage)}
-                            helpertext={touched.typebotRestartMessage && errors.typebotRestartMessage}
-                            variant="outlined"
-                            margin="dense"
-                            fullWidth
-                            className={classes.textField}
-                          />
-                        </Grid>
-                        
-                      </>
-                    )}
-                  </Grid>
-                </DialogContent>
-              </Paper>
-
-              <DialogActions>
-                {values.type === "dialogflow" && (
-                  <Button
-                    //type="submit"
-                    onClick={(e) => handleTestSession(e, values)}
-                    color="inherit"
-                    disabled={isSubmitting}
-                    name="testSession"
-                    variant="outlined"
-                    className={classes.btnLeft}
-                  >
-                    {i18n.t("queueIntegrationModal.buttons.test")}
-                  </Button>
-                )}
-                <Button
-                  onClick={handleClose}
-                  color="secondary"
-                  disabled={isSubmitting}
-                  variant="outlined"
-                >
-                  {i18n.t("queueIntegrationModal.buttons.cancel")}
-                </Button>
-                <Button
-                  type="submit"
-                  color="primary"
-                  disabled={isSubmitting}
-                  variant="contained"
-                  className={classes.btnWrapper}
-                >
-                  {integrationId
-                    ? `${i18n.t("queueIntegrationModal.buttons.okEdit")}`
-                    : `${i18n.t("queueIntegrationModal.buttons.okAdd")}`}
-                  {isSubmitting && (
-                    <CircularProgress
-                      size={24}
-                      className={classes.buttonProgress}
-                    />
-                  )}
-                </Button>
-              </DialogActions>
-            </Form>
-          )}
-        </Formik>
-      </Dialog>
-    </div >
-  );
-};
-
-export default QueueIntegration;

+ 0 - 510
frontend/src/components/QueueModal/index.js

@@ -1,510 +0,0 @@
-import React, { useState, useEffect, useRef } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import ColorPicker from "../ColorPicker";
-import {
-  FormControl,
-  Grid,
-  IconButton,
-  InputAdornment,
-  InputLabel,
-  MenuItem,
-  Paper,
-  Select,
-  Tab,
-  Tabs,
-} from "@material-ui/core";
-import { Colorize } from "@material-ui/icons";
-import { QueueOptions } from "../QueueOptions";
-import SchedulesForm from "../SchedulesForm";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: "flex",
-    flexWrap: "wrap",
-  },
-  textField: {
-    marginRight: theme.spacing(1),
-    flex: 1,
-  },
-
-  btnWrapper: {
-    position: "relative",
-  },
-
-  buttonProgress: {
-    color: green[500],
-    position: "absolute",
-    top: "50%",
-    left: "50%",
-    marginTop: -12,
-    marginLeft: -12,
-  },
-  formControl: {
-    margin: theme.spacing(1),
-    minWidth: 120,
-  },
-  colorAdorment: {
-    width: 20,
-    height: 20,
-  },
-}));
-
-const QueueSchema = Yup.object().shape({
-  name: Yup.string()
-    .min(2, i18n.t("queueModal.form.nameShort"))
-    .max(50, i18n.t("queueModal.form.nameLong"))
-    .required(i18n.t("queueModal.form.nameRequired")),
-  color: Yup.string()
-    .min(3, i18n.t("queueModal.form.colorShort"))
-    .max(9, i18n.t("queueModal.form.colorLong"))
-    .required(),
-  greetingMessage: Yup.string(),
-});
-
-const QueueModal = ({ open, onClose, queueId }) => {
-  const classes = useStyles();
-
-  const initialState = {
-    name: "",
-    color: "",
-    greetingMessage: "",
-    outOfHoursMessage: "",
-    orderQueue: "",
-    integrationId: "",
-    promptId: "",
-  };
-
-  const [colorPickerModalOpen, setColorPickerModalOpen] = useState(false);
-  const [queue, setQueue] = useState(initialState);
-  const [tab, setTab] = useState(0);
-  const [schedulesEnabled, setSchedulesEnabled] = useState(false);
-  const greetingRef = useRef();
-  const [integrations, setIntegrations] = useState([]);
-
-  const [schedules, setSchedules] = useState([
-    {
-      weekday: "Segunda-feira",
-      weekdayEn: "monday",
-      startTime: "08:00",
-      endTime: "18:00",
-    },
-    {
-      weekday: "Terça-feira",
-      weekdayEn: "tuesday",
-      startTime: "08:00",
-      endTime: "18:00",
-    },
-    {
-      weekday: "Quarta-feira",
-      weekdayEn: "wednesday",
-      startTime: "08:00",
-      endTime: "18:00",
-    },
-    {
-      weekday: "Quinta-feira",
-      weekdayEn: "thursday",
-      startTime: "08:00",
-      endTime: "18:00",
-    },
-    {
-      weekday: "Sexta-feira",
-      weekdayEn: "friday",
-      startTime: "08:00",
-      endTime: "18:00",
-    },
-    {
-      weekday: "Sábado",
-      weekdayEn: "saturday",
-      startTime: "08:00",
-      endTime: "12:00",
-    },
-    {
-      weekday: "Domingo",
-      weekdayEn: "sunday",
-      startTime: "00:00",
-      endTime: "00:00",
-    },
-  ]);
-  const [selectedPrompt, setSelectedPrompt] = useState(null);
-  const [prompts, setPrompts] = useState([]);
-
-  useEffect(() => {
-    (async () => {
-      try {
-        const { data } = await api.get("/prompt");
-        setPrompts(data.prompts);
-      } catch (err) {
-        toastError(err);
-      }
-    })();
-  }, []);
-
-  useEffect(() => {
-    api.get(`/settings`).then(({ data }) => {
-      if (Array.isArray(data)) {
-        const scheduleType = data.find((d) => d.key === "scheduleType");
-        if (scheduleType) {
-          setSchedulesEnabled(scheduleType.value === "queue");
-        }
-      }
-    });
-  }, []);
-
-  useEffect(() => {
-    (async () => {
-      try {
-        const { data } = await api.get("/queueIntegration");
-
-        setIntegrations(data.queueIntegrations);
-      } catch (err) {
-        toastError(err);
-      }
-    })();
-  }, []);
-
-  useEffect(() => {
-    (async () => {
-      if (!queueId) return;
-      try {
-        const { data } = await api.get(`/queue/${queueId}`);
-        setQueue((prevState) => {
-          return { ...prevState, ...data };
-        });
-        data.promptId
-          ? setSelectedPrompt(data.promptId)
-          : setSelectedPrompt(null);
-
-        setSchedules(data.schedules);
-      } catch (err) {
-        toastError(err);
-      }
-    })();
-
-    return () => {
-      setQueue({
-        name: "",
-        color: "",
-        greetingMessage: "",
-        outOfHoursMessage: "",
-        orderQueue: "",
-        integrationId: "",
-      });
-    };
-  }, [queueId, open]);
-
-  const handleClose = () => {
-    onClose();
-    setQueue(initialState);
-  };
-
-  const handleSaveQueue = async (values) => {
-    try {
-      if (queueId) {
-        await api.put(`/queue/${queueId}`, {
-          ...values,
-          schedules,
-          promptId: selectedPrompt ? selectedPrompt : null,
-        });
-      } else {
-        await api.post("/queue", {
-          ...values,
-          schedules,
-          promptId: selectedPrompt ? selectedPrompt : null,
-        });
-      }
-      toast.success(i18n.t("queueModal.toasts.success"));
-      handleClose();
-    } catch (err) {
-      toastError(err);
-    }
-  };
-
-  const handleSaveSchedules = async (values) => {
-    toast.success(i18n.t("queueModal.toasts.info"));
-    setSchedules(values);
-    setTab(0);
-  };
-
-  const handleChangePrompt = (e) => {
-    setSelectedPrompt(e.target.value);
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog
-        maxWidth="md"
-        fullWidth={true}
-        open={open}
-        onClose={handleClose}
-        scroll="paper"
-      >
-        <DialogTitle>
-          {queueId
-            ? `${i18n.t("queueModal.title.edit")}`
-            : `${i18n.t("queueModal.title.add")}`}
-        </DialogTitle>
-        <Tabs
-          value={tab}
-          indicatorColor="primary"
-          textColor="primary"
-          onChange={(_, v) => setTab(v)}
-          aria-label="disabled tabs example"
-        >
-          <Tab label={i18n.t("queueModal.tabs.queueData")} />
-          {schedulesEnabled && <Tab label={i18n.t("queueModal.tabs.attendanceTime")} />}
-        </Tabs>
-        {tab === 0 && (
-          <Paper>
-            <Formik
-              initialValues={queue}
-              enableReinitialize={true}
-              validationSchema={QueueSchema}
-              onSubmit={(values, actions) => {
-                setTimeout(() => {
-                  handleSaveQueue(values);
-                  actions.setSubmitting(false);
-                }, 400);
-              }}
-            >
-              {({ touched, errors, isSubmitting, values }) => (
-                <Form>
-                  <DialogContent dividers>
-                    <Field
-                      as={TextField}
-                      label={i18n.t("queueModal.form.name")}
-                      autoFocus
-                      name="name"
-                      error={touched.name && Boolean(errors.name)}
-                      helperText={touched.name && errors.name}
-                      variant="outlined"
-                      margin="dense"
-                      className={classes.textField}
-                    />
-                    <Field
-                      as={TextField}
-                      label={i18n.t("queueModal.form.color")}
-                      name="color"
-                      id="color"
-                      onFocus={() => {
-                        setColorPickerModalOpen(true);
-                        greetingRef.current.focus();
-                      }}
-                      error={touched.color && Boolean(errors.color)}
-                      helperText={touched.color && errors.color}
-                      InputProps={{
-                        startAdornment: (
-                          <InputAdornment position="start">
-                            <div
-                              style={{ backgroundColor: values.color }}
-                              className={classes.colorAdorment}
-                            ></div>
-                          </InputAdornment>
-                        ),
-                        endAdornment: (
-                          <IconButton
-                            size="small"
-                            color="default"
-                            onClick={() => setColorPickerModalOpen(true)}
-                          >
-                            <Colorize />
-                          </IconButton>
-                        ),
-                      }}
-                      variant="outlined"
-                      margin="dense"
-                      className={classes.textField}
-                    />
-                    <ColorPicker
-                      open={colorPickerModalOpen}
-                      handleClose={() => setColorPickerModalOpen(false)}
-                      onChange={(color) => {
-                        values.color = color;
-                        setQueue(() => {
-                          return { ...values, color };
-                        });
-                      }}
-                    />
-                    <Field
-                      as={TextField}
-                      label={i18n.t("queueModal.form.orderQueue")}
-                      name="orderQueue"
-                      type="orderQueue"
-                      error={touched.orderQueue && Boolean(errors.orderQueue)}
-                      helperText={touched.orderQueue && errors.orderQueue}
-                      variant="outlined"
-                      margin="dense"
-                      className={classes.textField1}
-                    />
-                    <div>
-                      <FormControl
-                        variant="outlined"
-                        margin="dense"
-                        className={classes.FormControl}
-                        fullWidth
-                      >
-                        <InputLabel id="integrationId-selection-label">
-                          {i18n.t("queueModal.form.integrationId")}
-                        </InputLabel>
-                        <Field
-                          as={Select}
-                          label={i18n.t("queueModal.form.integrationId")}
-                          name="integrationId"
-                          id="integrationId"
-                          placeholder={i18n.t("queueModal.form.integrationId")}
-                          labelId="integrationId-selection-label"
-                          value={values.integrationId || ""}
-                        >
-                          <MenuItem value={""}>{"Nenhum"}</MenuItem>
-                          {integrations.map((integration) => (
-                            <MenuItem
-                              key={integration.id}
-                              value={integration.id}
-                            >
-                              {integration.name}
-                            </MenuItem>
-                          ))}
-                        </Field>
-                      </FormControl>
-                      <FormControl margin="dense" variant="outlined" fullWidth>
-                        <InputLabel>
-                          {i18n.t("whatsappModal.form.prompt")}
-                        </InputLabel>
-                        <Select
-                          labelId="dialog-select-prompt-label"
-                          id="dialog-select-prompt"
-                          name="promptId"
-                          value={selectedPrompt || ""}
-                          onChange={handleChangePrompt}
-                          label={i18n.t("whatsappModal.form.prompt")}
-                          fullWidth
-                          MenuProps={{
-                            anchorOrigin: {
-                              vertical: "bottom",
-                              horizontal: "left",
-                            },
-                            transformOrigin: {
-                              vertical: "top",
-                              horizontal: "left",
-                            },
-                            getContentAnchorEl: null,
-                          }}
-                        >
-                          {prompts.map((prompt) => (
-                            <MenuItem key={prompt.id} value={prompt.id}>
-                              {prompt.name}
-                            </MenuItem>
-                          ))}
-                        </Select>
-                      </FormControl>
-                    </div>
-                    <div style={{ marginTop: 5 }}>
-                      <Field
-                        as={TextField}
-                        label={i18n.t("queueModal.form.greetingMessage")}
-                        type="greetingMessage"
-                        multiline
-                        inputRef={greetingRef}
-                        rows={5}
-                        fullWidth
-                        name="greetingMessage"
-                        error={
-                          touched.greetingMessage &&
-                          Boolean(errors.greetingMessage)
-                        }
-                        helperText={
-                          touched.greetingMessage && errors.greetingMessage
-                        }
-                        variant="outlined"
-                        margin="dense"
-                      />
-                      {schedulesEnabled && (
-                        <Field
-                          as={TextField}
-                          label={i18n.t("queueModal.form.outOfHoursMessage")}
-                          type="outOfHoursMessage"
-                          multiline
-                          inputRef={greetingRef}
-                          rows={5}
-                          fullWidth
-                          name="outOfHoursMessage"
-                          error={
-                            touched.outOfHoursMessage &&
-                            Boolean(errors.outOfHoursMessage)
-                          }
-                          helperText={
-                            touched.outOfHoursMessage &&
-                            errors.outOfHoursMessage
-                          }
-                          variant="outlined"
-                          margin="dense"
-                        />
-                      )}
-                    </div>
-                    <QueueOptions queueId={queueId} />
-                  </DialogContent>
-                  <DialogActions>
-                    <Button
-                      onClick={handleClose}
-                      color="secondary"
-                      disabled={isSubmitting}
-                      variant="outlined"
-                    >
-                      {i18n.t("queueModal.buttons.cancel")}
-                    </Button>
-                    <Button
-                      type="submit"
-                      color="primary"
-                      disabled={isSubmitting}
-                      variant="contained"
-                      className={classes.btnWrapper}
-                    >
-                      {queueId
-                        ? `${i18n.t("queueModal.buttons.okEdit")}`
-                        : `${i18n.t("queueModal.buttons.okAdd")}`}
-                      {isSubmitting && (
-                        <CircularProgress
-                          size={24}
-                          className={classes.buttonProgress}
-                        />
-                      )}
-                    </Button>
-                  </DialogActions>
-                </Form>
-              )}
-            </Formik>
-          </Paper>
-        )}
-        {tab === 1 && (
-          <Paper style={{ padding: 20 }}>
-            <SchedulesForm
-              loading={false}
-              onSubmit={handleSaveSchedules}
-              initialValues={schedules}
-              labelSaveButton={i18n.t("queueModal.buttons.okAdd")}
-            />
-          </Paper>
-        )}
-      </Dialog>
-    </div>
-  );
-};
-
-export default QueueModal;

+ 0 - 345
frontend/src/components/QueueOptions/index.js

@@ -1,345 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import Stepper from "@material-ui/core/Stepper";
-import Step from "@material-ui/core/Step";
-import StepLabel from "@material-ui/core/StepLabel";
-import Typography from "@material-ui/core/Typography";
-import { Button, IconButton, StepContent, TextField } from "@material-ui/core";
-import AddIcon from "@material-ui/icons/Add";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import SaveIcon from "@material-ui/icons/Save";
-import EditIcon from "@material-ui/icons/Edit";
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    width: "100%",
-    //height: 400,
-    [theme.breakpoints.down("sm")]: {
-      maxHeight: "20vh",
-    },
-  },
-  button: {
-    marginRight: theme.spacing(1),
-  },
-  input: {
-    marginTop: theme.spacing(1),
-    marginBottom: theme.spacing(1),
-  },
-  addButton: {
-    marginTop: theme.spacing(2),
-    marginBottom: theme.spacing(2),
-  },
-}));
-
-export function QueueOptionStepper({ queueId, options, updateOptions }) {
-  const classes = useStyles();
-  const [activeOption, setActiveOption] = useState(-1);
-
-  const handleOption = (index) => async () => {
-    setActiveOption(index);
-    const option = options[index];
-
-    if (option !== undefined && option.id !== undefined) {
-      try {
-        const { data } = await api.request({
-          url: "/queue-options",
-          method: "GET",
-          params: { queueId, parentId: option.id },
-        });
-        const optionList = data.map((option) => {
-          return {
-            ...option,
-            children: [],
-            edition: false,
-          };
-        });
-        option.children = optionList;
-        updateOptions();
-      } catch (e) {
-        toastError(e);
-      }
-    }
-  };
-
-  const handleSave = async (option) => {
-    try {
-      if (option.id) {
-        await api.request({
-          url: `/queue-options/${option.id}`,
-          method: "PUT",
-          data: option,
-        });
-      } else {
-        const { data } = await api.request({
-          url: `/queue-options`,
-          method: "POST",
-          data: option,
-        });
-        option.id = data.id;
-      }
-      option.edition = false;
-      updateOptions();
-    } catch (e) {
-      toastError(e);
-    }
-  };
-
-  const handleEdition = (index) => {
-    options[index].edition = !options[index].edition;
-    updateOptions();
-  };
-
-  const handleDeleteOption = async (index) => {
-    const option = options[index];
-    if (option !== undefined && option.id !== undefined) {
-      try {
-        await api.request({
-          url: `/queue-options/${option.id}`,
-          method: "DELETE",
-        });
-      } catch (e) {
-        toastError(e);
-      }
-    }
-    options.splice(index, 1);
-    options.forEach(async (option, order) => {
-      option.option = order + 1;
-      await handleSave(option);
-    });
-    updateOptions();
-  };
-
-  const handleOptionChangeTitle = (event, index) => {
-    options[index].title = event.target.value;
-    updateOptions();
-  };
-
-  const handleOptionChangeMessage = (event, index) => {
-    options[index].message = event.target.value;
-    updateOptions();
-  };
-
-  const renderTitle = (index) => {
-    const option = options[index];
-    if (option.edition) {
-      return (
-        <>
-          <TextField
-            value={option.title}
-            onChange={(event) => handleOptionChangeTitle(event, index)}
-            size="small"
-            className={classes.input}
-            placeholder="Título da opção"
-          />
-          {option.edition && (
-            <>
-              <IconButton
-                color="primary"
-                variant="outlined"
-                size="small"
-                className={classes.button}
-                onClick={() => handleSave(option)}
-              >
-                <SaveIcon />
-              </IconButton>
-              <IconButton
-                variant="outlined"
-                color="secondary"
-                size="small"
-                className={classes.button}
-                onClick={() => handleDeleteOption(index)}
-              >
-                <DeleteOutlineIcon />
-              </IconButton>
-            </>
-          )}
-        </>
-      );
-    }
-    return (
-      <>
-        <Typography>
-          {option.title !== "" ? option.title : "Título não definido"}
-          <IconButton
-            variant="outlined"
-            size="small"
-            className={classes.button}
-            onClick={() => handleEdition(index)}
-          >
-            <EditIcon />
-          </IconButton>
-        </Typography>
-      </>
-    );
-  };
-
-  const renderMessage = (index) => {
-    const option = options[index];
-    if (option.edition) {
-      return (
-        <>
-          <TextField
-            style={{ width: "100%" }}
-            multiline
-            value={option.message}
-            onChange={(event) => handleOptionChangeMessage(event, index)}
-            size="small"
-            className={classes.input}
-            placeholder="Digite o texto da opção"
-          />
-        </>
-      );
-    }
-    return (
-      <>
-        <Typography onClick={() => handleEdition(index)}>
-          {option.message}
-        </Typography>
-      </>
-    );
-  };
-
-  const handleAddOption = (index) => {
-    const optionNumber = options[index].children.length + 1;
-    options[index].children.push({
-      title: "",
-      message: "",
-      edition: false,
-      option: optionNumber,
-      queueId,
-      parentId: options[index].id,
-      children: [],
-    });
-    updateOptions();
-  };
-
-  const renderStep = (option, index) => {
-    return (
-      <Step key={index}>
-        <StepLabel style={{ cursor: "pointer" }} onClick={handleOption(index)}>
-          {renderTitle(index)}
-        </StepLabel>
-        <StepContent>
-          {renderMessage(index)}
-
-          {option.id !== undefined && (
-            <>
-              <Button
-                color="primary"
-                size="small"
-                onClick={() => handleAddOption(index)}
-                startIcon={<AddIcon />}
-                variant="outlined"
-                className={classes.addButton}
-              >
-                Adicionar
-              </Button>
-            </>
-          )}
-          <QueueOptionStepper
-            queueId={queueId}
-            options={option.children}
-            updateOptions={updateOptions}
-          />
-        </StepContent>
-      </Step>
-    );
-  };
-
-  const renderStepper = () => {
-    return (
-      <Stepper
-        style={{ marginBottom: 0, paddingBottom: 0 }}
-        nonLinear
-        activeStep={activeOption}
-        orientation="vertical"
-      >
-        {options.map((option, index) => renderStep(option, index))}
-      </Stepper>
-    );
-  };
-
-  return renderStepper();
-}
-
-export function QueueOptions({ queueId }) {
-  const classes = useStyles();
-  const [options, setOptions] = useState([]);
-
-  useEffect(() => {
-    if (queueId) {
-      const fetchOptions = async () => {
-        try {
-          const { data } = await api.request({
-            url: "/queue-options",
-            method: "GET",
-            params: { queueId, parentId: -1 },
-          });
-          const optionList = data.map((option) => {
-            return {
-              ...option,
-              children: [],
-              edition: false,
-            };
-          });
-          setOptions(optionList);
-        } catch (e) {
-          toastError(e);
-        }
-      };
-      fetchOptions();
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, []);
-
-  const renderStepper = () => {
-    if (options.length > 0) {
-      return (
-        <QueueOptionStepper
-          queueId={queueId}
-          updateOptions={updateOptions}
-          options={options}
-        />
-      );
-    }
-  };
-
-  const updateOptions = () => {
-    setOptions([...options]);
-  };
-
-  const addOption = () => {
-    const newOption = {
-      title: "",
-      message: "",
-      edition: false,
-      option: options.length + 1,
-      queueId,
-      parentId: null,
-      children: [],
-    };
-    setOptions([...options, newOption]);
-  };
-
-  return (
-    <div className={classes.root}>
-      <br />
-      <Typography>
-        Opções
-        <Button
-          color="primary"
-          size="small"
-          onClick={addOption}
-          startIcon={<AddIcon />}
-          style={{ marginLeft: 10 }}
-          variant="outlined"
-        >
-          Adicionar
-        </Button>
-      </Typography>
-      {renderStepper()}
-    </div>
-  );
-}

+ 0 - 90
frontend/src/components/QueueSelect/index copy.js

@@ -1,90 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import Chip from "@material-ui/core/Chip";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles(theme => ({
-	chips: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	chip: {
-		margin: 2,
-	},
-}));
-
-const QueueSelect = ({ selectedQueueIds, onChange }) => {
-	const classes = useStyles();
-	const [queues, setQueues] = useState([]);
-
-	useEffect(() => {
-		(async () => {
-			try {
-				const { data } = await api.get("/queue");
-				setQueues(data);
-			} catch (err) {
-				toastError(err);
-			}
-		})();
-	}, []);
-
-	const handleChange = e => {
-		onChange(e.target.value);
-	};
-
-	return (
-		<div style={{ marginTop: 6 }}>
-			<FormControl fullWidth margin="dense" variant="outlined">
-				<InputLabel>{i18n.t("queueSelect.inputLabel")}</InputLabel>
-				<Select
-					multiple
-					labelWidth={60}
-					value={selectedQueueIds}
-					onChange={handleChange}
-					MenuProps={{
-						anchorOrigin: {
-							vertical: "bottom",
-							horizontal: "left",
-						},
-						transformOrigin: {
-							vertical: "top",
-							horizontal: "left",
-						},
-						getContentAnchorEl: null,
-					}}
-					renderValue={selected => (
-						<div className={classes.chips}>
-							{selected?.length > 0 &&
-								selected.map(id => {
-									const queue = queues.find(q => q.id === id);
-									return queue ? (
-										<Chip
-											key={id}
-											style={{ backgroundColor: queue.color }}
-											variant="outlined"
-											label={queue.name}
-											className={classes.chip}
-										/>
-									) : null;
-								})}
-						</div>
-					)}
-				>
-					{queues.map(queue => (
-						<MenuItem key={queue.id} value={queue.id}>
-							{queue.name}
-						</MenuItem>
-					))}
-				</Select>
-			</FormControl>
-		</div>
-	);
-};
-
-export default QueueSelect;

+ 0 - 112
frontend/src/components/QueueSelect/index.js

@@ -1,112 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import Chip from "@material-ui/core/Chip";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles(theme => ({
-	chips: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	chip: {
-		margin: 2,
-	},
-}));
-
-const QueueSelect = ({ selectedQueueIds, onChange, multiple = true, title = i18n.t("queueSelect.inputLabel") }) => {
-	const classes = useStyles();
-	const [queues, setQueues] = useState([]);
-
-	useEffect(() => {
-
-		fetchQueues();
-
-	}, []);
-
-	const fetchQueues = async () => {
-		try {
-			const { data } = await api.get("/queue");
-			setQueues(data);
-		} catch (err) {
-			toastError(err);
-		}
-	}
-
-	const handleChange = e => {
-		onChange(e.target.value);
-	};
-
-	return (
-		<div >
-			<FormControl fullWidth margin="dense" variant="outlined">
-				<InputLabel shrink={selectedQueueIds ? true : false} >{title}</InputLabel>
-				<Select
-					label={title}
-					multiple={multiple}
-					labelWidth={60}
-					value={selectedQueueIds}
-					onChange={handleChange}
-					MenuProps={{
-						anchorOrigin: {
-							vertical: "bottom",
-							horizontal: "left",
-						},
-						transformOrigin: {
-							vertical: "top",
-							horizontal: "left",
-						},
-						getContentAnchorEl: null,
-					}}
-
-					renderValue={selected => {
-						return (
-							<div className={classes.chips}>
-								{selected?.length > 0 && multiple ? (
-									selected.map(id => {
-										const queue = queues.find(q => q.id === id);
-										return queue ? (
-											<Chip
-												key={id}
-												style={{ backgroundColor: queue.color }}
-												variant="outlined"
-												label={queue.name}
-												className={classes.chip}
-											/>
-										) : null;
-									})
-
-								) :
-									(
-										<Chip
-											key={selected}
-											variant="outlined"
-											style={{ backgroundColor: queues.find(q => q.id === selected)?.color }}
-											label={queues.find(q => q.id === selected)?.name}
-											className={classes.chip}
-										/>
-									)
-								}
-
-							</div>
-						)
-					}}
-				>
-					{!multiple && <MenuItem value={null}>Nenhum</MenuItem>}
-					{queues.map(queue => (
-						<MenuItem key={queue.id} value={queue.id}>
-							{queue.name}
-						</MenuItem>
-					))}
-				</Select>
-			</FormControl>
-		</div>
-	);
-};
-
-export default QueueSelect;

+ 0 - 90
frontend/src/components/QueueSelect/index_erro.js

@@ -1,90 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import Chip from "@material-ui/core/Chip";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles(theme => ({
-	chips: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	chip: {
-		margin: 2,
-	},
-}));
-
-const QueueSelect = ({ selectedQueueIds, onChange }) => {
-	const classes = useStyles();
-	const [queues, setQueues] = useState([]);
-
-	useEffect(() => {
-		(async () => {
-			try {
-				const { data } = await api.get("/queue");
-				setQueues(data);
-			} catch (err) {
-				toastError(err);
-			}
-		})();
-	}, []);
-
-	const handleChange = e => {
-		onChange(e.target.value);
-	};
-
-	return (
-		<div style={{ marginTop: 6 }}>
-			<FormControl fullWidth margin="dense" variant="outlined">
-				<InputLabel>{i18n.t("queueSelect.inputLabel")}</InputLabel>
-				<Select
-					multiple
-					labelWidth={60}
-					value={selectedQueueIds}
-					onChange={handleChange}
-					MenuProps={{
-						anchorOrigin: {
-							vertical: "bottom",
-							horizontal: "left",
-						},
-						transformOrigin: {
-							vertical: "top",
-							horizontal: "left",
-						},
-						getContentAnchorEl: null,
-					}}
-					renderValue={selected => (
-						<div className={classes.chips}>
-							{selected?.length > 0 &&
-								selected.map(id => {
-									const queue = queues.find(q => q.id === id);
-									return queue ? (
-										<Chip
-											key={id}
-											style={{ backgroundColor: queue.color }}
-											variant="outlined"
-											label={queue.name}
-											className={classes.chip}
-										/>
-									) : null;
-								})}
-						</div>
-					)}
-				>
-					{queues.map(queue => (
-						<MenuItem key={queue.id} value={queue.id}>
-							{queue.name}
-						</MenuItem>
-					))}
-				</Select>
-			</FormControl>
-		</div>
-	);
-};
-
-export default QueueSelect;

+ 0 - 92
frontend/src/components/QueueSelectCustom/index.js

@@ -1,92 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { makeStyles } from "@material-ui/core/styles";
-import InputLabel from "@material-ui/core/InputLabel";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import Chip from "@material-ui/core/Chip";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles(theme => ({
-	chips: {
-		display: "flex",
-		flexWrap: "wrap",
-	},
-	chip: {
-		margin: 2,
-	},
-}));
-
-const QueueSelectCustom = ({ selectedQueueIds, companyId, onChange }) => {
-	const classes = useStyles();
-	const [queues, setQueues] = useState([]);
-
-	useEffect(() => {
-		(async () => {
-			try {
-				const { data } = await api.get("/queue", {
-					params: { companyId }
-				});
-				setQueues(data);
-			} catch (err) {
-				toastError(err);
-			}
-		})();
-	}, [companyId]);
-
-	const handleChange = e => {
-		onChange(e.target.value);
-	};
-
-	return (
-		<div style={{ marginTop: 6 }}>
-			<FormControl fullWidth margin="dense" variant="outlined">
-				<InputLabel>{i18n.t("queueSelect.inputLabel")}</InputLabel>
-				<Select
-					multiple
-					labelWidth={60}
-					value={selectedQueueIds}
-					onChange={handleChange}
-					MenuProps={{
-						anchorOrigin: {
-							vertical: "bottom",
-							horizontal: "left",
-						},
-						transformOrigin: {
-							vertical: "top",
-							horizontal: "left",
-						},
-						getContentAnchorEl: null,
-					}}
-					renderValue={selected => (
-						<div className={classes.chips}>
-							{selected?.length > 0 &&
-								selected.map(id => {
-									const queue = queues.find(q => q.id === id);
-									return queue ? (
-										<Chip
-											key={id}
-											style={{ backgroundColor: queue.color }}
-											variant="outlined"
-											label={queue.name}
-											className={classes.chip}
-										/>
-									) : null;
-								})}
-						</div>
-					)}
-				>
-					{queues.map(queue => (
-						<MenuItem key={queue.id} value={queue.id}>
-							{queue.name}
-						</MenuItem>
-					))}
-				</Select>
-			</FormControl>
-		</div>
-	);
-};
-
-export default QueueSelectCustom;

+ 0 - 68
frontend/src/components/QueueSelectSingle/index.js

@@ -1,68 +0,0 @@
-import React, { useEffect, useState } from "react";
-import { Field } from "formik";
-import { makeStyles } from "@material-ui/core/styles";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import Select from "@material-ui/core/Select";
-import toastError from "../../errors/toastError";
-import api from "../../services/api";
-import { i18n } from "../../translate/i18n";
-import Typography from "@material-ui/core/Typography";
-
-const useStyles = makeStyles(theme => ({
-    formControl: {
-        margin: theme.spacing(1),
-        minWidth: 120,
-    },
-}));
-
-const QueueSelectSingle = (touched, errors) => {
-    const classes = useStyles();
-    const [queues, setQueues] = useState([]);
-
-    useEffect(() => {
-        (async () => {
-            try {
-                const { data } = await api.get("/queue");
-                setQueues(data);
-            } catch (err) {
-                toastError(`QUEUESELETSINGLE >>> ${err}`);
-            }
-        })();
-    }, []);
-
-    return (
-        <div style={{ marginTop: 6 }}>
-            <FormControl
-                variant="outlined"
-                className={classes.FormControl}
-                margin="dense"
-                fullWidth
-            >
-                <div>
-                    <Typography>
-                        {i18n.t("queueSelect.inputLabel")}
-                    </Typography>
-                    <Field
-                        as={Select}
-                        label={i18n.t("queueSelect.inputLabel")}
-                        name="queueId"
-                        labelId="queue-selection-label"
-                        id="queue-selection"
-                        error={touched.queueId && Boolean(errors.queueId)}
-                        helpertext={touched.name && errors.name}
-                        fullWidth
-                    >
-                        {queues.map(queue => (
-                            <MenuItem key={queue.id} value={queue.id}>
-                                {queue.name}
-                            </MenuItem>
-                        ))}
-                    </Field>
-                </div>
-            </FormControl>
-        </div>
-    );
-};
-
-export default QueueSelectSingle;

+ 0 - 332
frontend/src/components/QuickMessageDialog/index.js

@@ -1,332 +0,0 @@
-import React, { useContext, useState, useEffect, useRef } 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 Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-import AttachFileIcon from "@material-ui/icons/AttachFile";
-import DeleteOutlineIcon from "@material-ui/icons/DeleteOutline";
-import IconButton from "@material-ui/core/IconButton";
-import { i18n } from "../../translate/i18n";
-import { head } from "lodash";
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { AuthContext } from "../../context/Auth/AuthContext";
-import MessageVariablesPicker from "../MessageVariablesPicker";
-import ButtonWithSpinner from "../ButtonWithSpinner";
-
-import {
-    FormControl,
-    Grid,
-    InputLabel,
-    MenuItem,
-    Select,
-} from "@material-ui/core";
-import ConfirmationModal from "../ConfirmationModal";
-
-const path = require('path');
-
-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,
-    },
-    formControl: {
-        margin: theme.spacing(1),
-        minWidth: 120,
-    },
-    colorAdorment: {
-        width: 20,
-        height: 20,
-    },
-}));
-
-const QuickeMessageSchema = Yup.object().shape({
-    shortcode: Yup.string().required("Obrigatório"),
-    //   message: Yup.string().required("Obrigatório"),
-});
-
-const QuickMessageDialog = ({ open, onClose, quickemessageId, reload }) => {
-    const classes = useStyles();
-    const { user } = useContext(AuthContext);
-    const { profile } = user;
-    const messageInputRef = useRef();
-
-    const initialState = {
-        shortcode: "",
-        message: "",
-        geral: false,
-        status: true,
-    };
-
-    const [confirmationOpen, setConfirmationOpen] = useState(false);
-    const [quickemessage, setQuickemessage] = useState(initialState);
-    const [attachment, setAttachment] = useState(null);
-    const attachmentFile = useRef(null);
-
-    useEffect(() => {
-        try {
-            (async () => {
-                if (!quickemessageId) return;
-
-                const { data } = await api.get(`/quick-messages/${quickemessageId}`);
-
-                setQuickemessage((prevState) => {
-                    return { ...prevState, ...data };
-                });
-            })();
-        } catch (err) {
-            toastError(err);
-        }
-    }, [quickemessageId, open]);
-
-    const handleClose = () => {
-        setQuickemessage(initialState);
-        setAttachment(null);
-        onClose();
-    };
-
-    const handleAttachmentFile = (e) => {
-      
-        const file = head(e.target.files);
-        if (file) {
-            setAttachment(file);
-        }
-    };
-
-    const handleSaveQuickeMessage = async (values) => {
-
-        const quickemessageData = { ...values, isMedia: true, mediaPath: attachment ? String(attachment.name).replace(/ /g, "_") : values.mediaPath ? path.basename(values.mediaPath).replace(/ /g, "_") : null };
-
-        try {
-            if (quickemessageId) {
-                await api.put(`/quick-messages/${quickemessageId}`, quickemessageData);
-                if (attachment != null) {
-                    const formData = new FormData();
-                    formData.append("typeArch", "quickMessage");
-                    formData.append("file", attachment);
-                    await api.post(
-                        `/quick-messages/${quickemessageId}/media-upload`,
-                        formData
-                    );
-                }
-            } else {
-                const { data } = await api.post("/quick-messages", quickemessageData);
-                if (attachment != null) {
-                    const formData = new FormData();
-                    formData.append("typeArch", "quickMessage");
-                    formData.append("file", attachment);
-                    await api.post(`/quick-messages/${data.id}/media-upload`, formData);
-                }
-            }
-            toast.success(i18n.t("quickMessages.toasts.success"));
-            if (typeof reload == "function") {
-
-                reload();
-            }
-        } catch (err) {
-            toastError(err);
-        }
-        handleClose();
-    };
-
-    const deleteMedia = async () => {
-        if (attachment) {
-            setAttachment(null);
-            attachmentFile.current.value = null;
-        }
-
-        if (quickemessage.mediaPath) {
-            await api.delete(`/quick-messages/${quickemessage.id}/media-upload`);
-            setQuickemessage((prev) => ({
-                ...prev,
-                mediaPath: null,
-            }));
-            toast.success(i18n.t("quickMessages.toasts.deleted"));
-            if (typeof reload == "function") {
-
-                reload();
-            }
-        }
-    };
-
-    const handleClickMsgVar = async (msgVar, setValueFunc) => {
-        const el = messageInputRef.current;
-        const firstHalfText = el.value.substring(0, el.selectionStart);
-        const secondHalfText = el.value.substring(el.selectionEnd);
-        const newCursorPos = el.selectionStart + msgVar.length;
-
-        setValueFunc("message", `${firstHalfText}${msgVar}${secondHalfText}`);
-
-        await new Promise(r => setTimeout(r, 100));
-        messageInputRef.current.setSelectionRange(newCursorPos, newCursorPos);
-    };
-
-    return (
-        <div className={classes.root}>
-            <ConfirmationModal
-                title={i18n.t("quickMessages.confirmationModal.deleteTitle")}
-                open={confirmationOpen}
-                onClose={() => setConfirmationOpen(false)}
-                onConfirm={deleteMedia}
-            >
-                {i18n.t("quickMessages.confirmationModal.deleteMessage")}
-            </ConfirmationModal>
-            <Dialog
-                open={open}
-                onClose={handleClose}
-                maxWidth="xs"
-                fullWidth
-                scroll="paper"
-            >
-                <DialogTitle id="form-dialog-title">
-                    {quickemessageId
-                        ? `${i18n.t("quickMessages.dialog.edit")}`
-                        : `${i18n.t("quickMessages.dialog.add")}`}
-                </DialogTitle>
-                <div style={{ display: "none" }}>
-                    <input
-                        type="file"
-                        ref={attachmentFile}
-                        onChange={(e) => handleAttachmentFile(e)}
-                    />
-                </div>
-                <Formik
-                    initialValues={quickemessage}
-                    enableReinitialize={true}
-                    validationSchema={QuickeMessageSchema}
-                    onSubmit={(values, actions) => {
-                        setTimeout(() => {
-                            handleSaveQuickeMessage(values);
-                            actions.setSubmitting(false);
-                        }, 400);
-                    }}
-                >
-                    {({ touched, errors, isSubmitting, setFieldValue, values }) => (
-                        <Form>
-                            <DialogContent dividers>
-                                <Grid spacing={2} container>
-                                    <Grid xs={12} item>
-                                        <Field
-                                            as={TextField}
-                                            autoFocus
-                                            label={i18n.t("quickMessages.dialog.shortcode")}
-                                            name="shortcode"
-                                            error={touched.shortcode && Boolean(errors.shortcode)}
-                                            helperText={touched.shortcode && errors.shortcode}
-                                            variant="outlined"
-                                            margin="dense"
-                                            fullWidth
-                                        />
-                                    </Grid>
-                                    <Grid xs={12} item>
-                                        <Field
-                                            as={TextField}
-                                            label={i18n.t("quickMessages.dialog.message")}
-                                            name="message"
-                                            inputRef={messageInputRef}
-                                            error={touched.message && Boolean(errors.message)}
-                                            helperText={touched.message && errors.message}
-                                            variant="outlined"
-                                            margin="dense"
-                                            multiline={true}
-                                            rows={7}
-                                            fullWidth
-                                        // disabled={quickemessage.mediaPath || attachment ? true : false}
-                                        />
-                                    </Grid>
-                                    <Grid item>
-                                        <MessageVariablesPicker
-                                            disabled={isSubmitting}
-                                            onClick={value => handleClickMsgVar(value, setFieldValue)}
-                                        />
-                                    </Grid>
-                                    {(quickemessage.mediaPath || attachment) && (
-                                        <Grid xs={12} item>
-                                            <Button startIcon={<AttachFileIcon />}>
-                                                {attachment ? attachment.name : quickemessage.mediaName}
-                                            </Button>
-                                            <IconButton
-                                                onClick={() => setConfirmationOpen(true)}
-                                                color="secondary"
-                                            >
-                                                <DeleteOutlineIcon color="secondary" />
-                                            </IconButton>
-                                        </Grid>
-                                    )}
-                                </Grid>
-                            </DialogContent>
-                            <DialogActions>
-                                {!attachment && !quickemessage.mediaPath && (
-                                    <Button
-                                        color="primary"
-                                        onClick={() => attachmentFile.current.click()}
-                                        disabled={isSubmitting}
-                                        variant="outlined"
-                                    >
-                                        {i18n.t("quickMessages.buttons.attach")}
-                                    </Button>
-                                )}
-                                <Button
-                                    onClick={handleClose}
-                                    color="secondary"
-                                    disabled={isSubmitting}
-                                    variant="outlined"
-                                >
-                                    {i18n.t("quickMessages.buttons.cancel")}
-                                </Button>
-                                <Button
-                                    type="submit"
-                                    color="primary"
-                                    disabled={isSubmitting}
-                                    variant="contained"
-                                    className={classes.btnWrapper}
-                                >
-                                    {quickemessageId
-                                        ? `${i18n.t("quickMessages.buttons.edit")}`
-                                        : `${i18n.t("quickMessages.buttons.add")}`}
-                                    {isSubmitting && (
-                                        <CircularProgress
-                                            size={24}
-                                            className={classes.buttonProgress}
-                                        />
-                                    )}
-                                </Button>
-                            </DialogActions>
-                        </Form>
-                    )}
-                </Formik>
-            </Dialog>
-        </div>
-    );
-};
-
-export default QuickMessageDialog;

+ 0 - 93
frontend/src/components/QuickMessagesTable/index.js

@@ -1,93 +0,0 @@
-import React, { useState, useEffect } from "react";
-import PropTypes from "prop-types";
-import { 
-    Table,
-    TableHead,
-    TableBody,
-    TableCell,
-    TableRow,
-    IconButton
-} from '@material-ui/core';
-import {
-    Edit as EditIcon,
-    DeleteOutline as DeleteOutlineIcon
-} from "@material-ui/icons";
-
-import TableRowSkeleton from "../../components/TableRowSkeleton";
-
-function QuickMessagesTable(props) {
-    const { messages, showLoading, editMessage, deleteMessage, readOnly } = props
-    const [loading, setLoading] = useState(true)
-    const [rows, setRows] = useState([])
-
-    useEffect(() => {
-        if (Array.isArray(messages)) {
-            setRows(messages)
-        }
-        if (showLoading !== undefined) {
-            setLoading(showLoading)    
-        }
-    }, [messages, showLoading])
-
-    const handleEdit = (message) => {
-        editMessage(message)
-    }
-
-    const handleDelete = (message) => {
-        deleteMessage(message)
-    }
-
-    const renderRows = () => {
-        return rows.map((message) => {
-            return (
-                <TableRow key={message.id}>
-                    <TableCell align="center">{message.shortcode}</TableCell>
-                    <TableCell align="left">{message.message}</TableCell>
-                    { !readOnly ? (
-                        <TableCell align="center">
-                            <IconButton
-                                size="small"
-                                onClick={() => handleEdit(message)}
-                            >
-                                <EditIcon />
-                            </IconButton>
-
-                            <IconButton
-                                size="small"
-                                onClick={() => handleDelete(message)}
-                            >
-                                <DeleteOutlineIcon />
-                            </IconButton>
-                        </TableCell>
-                    ) : null}
-                </TableRow>
-            )
-        })
-    }
-
-    return (
-        <Table size="small">
-            <TableHead>
-                <TableRow>
-                    <TableCell align="center">Atalho</TableCell>
-                    <TableCell align="left">Mensagem</TableCell>
-                    { !readOnly ? (
-                        <TableCell align="center">Ações</TableCell>
-                    ) : null}
-                </TableRow>
-            </TableHead>
-            <TableBody>
-                {loading ? <TableRowSkeleton columns={readOnly ? 2 : 3} /> : renderRows()}
-            </TableBody>
-        </Table>
-    )
-}
-
-QuickMessagesTable.propTypes = {
-    messages: PropTypes.array.isRequired,
-    showLoading: PropTypes.bool,
-    editMessage: PropTypes.func.isRequired,
-    deleteMessage: PropTypes.func.isRequired
-}
-
-export default QuickMessagesTable;

+ 0 - 382
frontend/src/components/ScheduleModal/index.js

@@ -1,382 +0,0 @@
-import React, { useState, useEffect, useContext, useRef } from "react";
-
-import * as Yup from "yup";
-import { Formik, Form, Field } from "formik";
-import { toast } from "react-toastify";
-import { useHistory } from "react-router-dom";
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import Button from "@material-ui/core/Button";
-import TextField from "@material-ui/core/TextField";
-import Dialog from "@material-ui/core/Dialog";
-import DialogActions from "@material-ui/core/DialogActions";
-import DialogContent from "@material-ui/core/DialogContent";
-import DialogTitle from "@material-ui/core/DialogTitle";
-import CircularProgress from "@material-ui/core/CircularProgress";
-
-import { i18n } from "../../translate/i18n";
-
-import api from "../../services/api";
-import toastError from "../../errors/toastError";
-import { FormControl, Grid, IconButton } from "@material-ui/core";
-import Autocomplete from "@material-ui/lab/Autocomplete";
-import moment from "moment"
-import { AuthContext } from "../../context/Auth/AuthContext";
-import { isArray, capitalize } from "lodash";
-import DeleteOutline from "@material-ui/icons/DeleteOutline";
-import AttachFile from "@material-ui/icons/AttachFile";
-import { head } from "lodash";
-import ConfirmationModal from "../ConfirmationModal";
-import MessageVariablesPicker from "../MessageVariablesPicker";
-
-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,
-	},
-	formControl: {
-		margin: theme.spacing(1),
-		minWidth: 120,
-	},
-}));
-
-const ScheduleSchema = Yup.object().shape({
-	body: Yup.string()
-		.min(5, "Mensagem muito curta")
-		.required("Obrigatório"),
-	contactId: Yup.number().required("Obrigatório"),
-	sendAt: Yup.string().required("Obrigatório")
-});
-
-const ScheduleModal = ({ open, onClose, scheduleId, contactId, cleanContact, reload }) => {
-	const classes = useStyles();
-	const history = useHistory();
-	const { user } = useContext(AuthContext);
-
-	const initialState = {
-		body: "",
-		contactId: "",
-		sendAt: moment().add(1, 'hour').format('YYYY-MM-DDTHH:mm'),
-		sentAt: ""
-	};
-
-	const initialContact = {
-		id: "",
-		name: ""
-	}
-
-	const [schedule, setSchedule] = useState(initialState);
-	const [currentContact, setCurrentContact] = useState(initialContact);
-	const [contacts, setContacts] = useState([initialContact]);
-	const [attachment, setAttachment] = useState(null);
-	const attachmentFile = useRef(null);
-	const [confirmationOpen, setConfirmationOpen] = useState(false);
-	const messageInputRef = useRef();
-
-	useEffect(() => {
-		if (contactId && contacts.length) {
-			const contact = contacts.find(c => c.id === contactId);
-			if (contact) {
-				setCurrentContact(contact);
-			}
-		}
-	}, [contactId, contacts]);
-
-	useEffect(() => {
-		const { companyId } = user;
-		if (open) {
-			try {
-				(async () => {
-					const { data: contactList } = await api.get('/contacts/list', { params: { companyId: companyId } });
-					let customList = contactList.map((c) => ({ id: c.id, name: c.name }));
-					if (isArray(customList)) {
-						setContacts([{ id: "", name: "" }, ...customList]);
-					}
-					if (contactId) {
-						setSchedule(prevState => {
-							return { ...prevState, contactId }
-						});
-					}
-
-					if (!scheduleId) return;
-
-					const { data } = await api.get(`/schedules/${scheduleId}`);
-					setSchedule(prevState => {
-						return { ...prevState, ...data, sendAt: moment(data.sendAt).format('YYYY-MM-DDTHH:mm') };
-					});
-					setCurrentContact(data.contact);
-				})()
-			} catch (err) {
-				toastError(err);
-			}
-		}
-	}, [scheduleId, contactId, open, user]);
-
-	const handleClose = () => {
-		onClose();
-		setAttachment(null);
-		setSchedule(initialState);
-	};
-
-	const handleAttachmentFile = (e) => {
-		const file = head(e.target.files);
-		if (file) {
-			setAttachment(file);
-		}
-	};
-
-	const handleSaveSchedule = async values => {
-		const scheduleData = { ...values, userId: user.id };
-		try {
-			if (scheduleId) {
-				await api.put(`/schedules/${scheduleId}`, scheduleData);
-				if (attachment != null) {
-					const formData = new FormData();
-					formData.append("file", attachment);
-					await api.post(
-						`/schedules/${scheduleId}/media-upload`,
-						formData
-					);
-				}
-			} else {
-				const { data } = await api.post("/schedules", scheduleData);
-				if (attachment != null) {
-					const formData = new FormData();
-					formData.append("file", attachment);
-					await api.post(`/schedules/${data.id}/media-upload`, formData);
-				}
-			}
-			toast.success(i18n.t("scheduleModal.success"));
-			if (typeof reload == 'function') {
-				reload();
-			}
-			if (contactId) {
-				if (typeof cleanContact === 'function') {
-					cleanContact();
-					history.push('/schedules');
-				}
-			}
-		} catch (err) {
-			toastError(err);
-		}
-		setCurrentContact(initialContact);
-		setSchedule(initialState);
-		handleClose();
-	};
-	const handleClickMsgVar = async (msgVar, setValueFunc) => {
-		const el = messageInputRef.current;
-		const firstHalfText = el.value.substring(0, el.selectionStart);
-		const secondHalfText = el.value.substring(el.selectionEnd);
-		const newCursorPos = el.selectionStart + msgVar.length;
-
-		setValueFunc("body", `${firstHalfText}${msgVar}${secondHalfText}`);
-
-		await new Promise(r => setTimeout(r, 100));
-		messageInputRef.current.setSelectionRange(newCursorPos, newCursorPos);
-	};
-
-	const deleteMedia = async () => {
-		if (attachment) {
-			setAttachment(null);
-			attachmentFile.current.value = null;
-		}
-
-		if (schedule.mediaPath) {
-			await api.delete(`/schedules/${schedule.id}/media-upload`);
-			setSchedule((prev) => ({
-				...prev,
-				mediaPath: null,
-			}));
-			toast.success(i18n.t("scheduleModal.toasts.deleted"));
-			if (typeof reload == "function") {
-				console.log(reload);
-				console.log("1");
-				reload();
-			}
-		}
-	};
-
-	return (
-		<div className={classes.root}>
-			<ConfirmationModal
-				title={i18n.t("scheduleModal.confirmationModal.deleteTitle")}
-				open={confirmationOpen}
-				onClose={() => setConfirmationOpen(false)}
-				onConfirm={deleteMedia}
-			>
-				{i18n.t("scheduleModal.confirmationModal.deleteMessage")}
-			</ConfirmationModal>
-			<Dialog
-				open={open}
-				onClose={handleClose}
-				maxWidth="xs"
-				fullWidth
-				scroll="paper"
-			>
-				<DialogTitle id="form-dialog-title">
-					{schedule.status === 'ERRO' ? 'Erro de Envio' : `Mensagem ${capitalize(schedule.status)}`}
-				</DialogTitle>
-				<div style={{ display: "none" }}>
-					<input
-						type="file"
-						accept=".png,.jpg,.jpeg"
-						ref={attachmentFile}
-						onChange={(e) => handleAttachmentFile(e)}
-					/>
-				</div>
-				<Formik
-					initialValues={schedule}
-					enableReinitialize={true}
-					validationSchema={ScheduleSchema}
-					onSubmit={(values, actions) => {
-						setTimeout(() => {
-							handleSaveSchedule(values);
-							actions.setSubmitting(false);
-						}, 400);
-					}}
-				>
-					{({ touched, errors, isSubmitting, values, setFieldValue }) => (
-						<Form>
-							<DialogContent dividers>
-								<div className={classes.multFieldLine}>
-									<FormControl
-										variant="outlined"
-										fullWidth
-									>
-										<Autocomplete
-											fullWidth
-											value={currentContact}
-											options={contacts}
-											onChange={(e, contact) => {
-												const contactId = contact ? contact.id : '';
-												setSchedule({ ...schedule, contactId });
-												setCurrentContact(contact ? contact : initialContact);
-											}}
-											getOptionLabel={(option) => option.name}
-											getOptionSelected={(option, value) => {
-												return value.id === option.id
-											}}
-											renderInput={(params) => <TextField {...params} variant="outlined" placeholder="Contato" />}
-										/>
-									</FormControl>
-								</div>
-								<br />
-								<div className={classes.multFieldLine}>
-									<Field
-										as={TextField}
-										rows={9}
-										multiline={true}
-										label={i18n.t("scheduleModal.form.body")}
-										name="body"
-										inputRef={messageInputRef}
-										error={touched.body && Boolean(errors.body)}
-										helperText={touched.body && errors.body}
-										variant="outlined"
-										margin="dense"
-										fullWidth
-									/>
-								</div>
-								<Grid item>
-									<MessageVariablesPicker
-										disabled={isSubmitting}
-										onClick={value => handleClickMsgVar(value, setFieldValue)}
-									/>
-								</Grid>
-								<br />
-								<div className={classes.multFieldLine}>
-									<Field
-										as={TextField}
-										label={i18n.t("scheduleModal.form.sendAt")}
-										type="datetime-local"
-										name="sendAt"
-										InputLabelProps={{
-											shrink: true,
-										}}
-										error={touched.sendAt && Boolean(errors.sendAt)}
-										helperText={touched.sendAt && errors.sendAt}
-										variant="outlined"
-										fullWidth
-									/>
-								</div>
-								{(schedule.mediaPath || attachment) && (
-									<Grid xs={12} item>
-										<Button startIcon={<AttachFile />}>
-											{attachment ? attachment.name : schedule.mediaName}
-										</Button>
-										<IconButton
-											onClick={() => setConfirmationOpen(true)}
-											color="secondary"
-										>
-											<DeleteOutline color="secondary" />
-										</IconButton>
-									</Grid>
-								)}
-							</DialogContent>
-							<DialogActions>
-								{!attachment && !schedule.mediaPath && (
-									<Button
-										color="primary"
-										onClick={() => attachmentFile.current.click()}
-										disabled={isSubmitting}
-										variant="outlined"
-									>
-										{i18n.t("quickMessages.buttons.attach")}
-									</Button>
-								)}
-								<Button
-									onClick={handleClose}
-									color="secondary"
-									disabled={isSubmitting}
-									variant="outlined"
-								>
-									{i18n.t("scheduleModal.buttons.cancel")}
-								</Button>
-								{(schedule.sentAt === null || schedule.sentAt === "") && (
-									<Button
-										type="submit"
-										color="primary"
-										disabled={isSubmitting}
-										variant="contained"
-										className={classes.btnWrapper}
-									>
-										{scheduleId
-											? `${i18n.t("scheduleModal.buttons.okEdit")}`
-											: `${i18n.t("scheduleModal.buttons.okAdd")}`}
-										{isSubmitting && (
-											<CircularProgress
-												size={24}
-												className={classes.buttonProgress}
-											/>
-										)}
-									</Button>
-								)}
-							</DialogActions>
-						</Form>
-					)}
-				</Formik>
-			</Dialog>
-		</div>
-	);
-};
-
-export default ScheduleModal;

+ 0 - 141
frontend/src/components/SchedulesForm/index.js

@@ -1,141 +0,0 @@
-import React, { useState, useEffect } from "react";
-import { makeStyles, TextField, Grid, Container } from "@material-ui/core";
-import { Formik, Form, FastField, FieldArray } from "formik";
-import { isArray } from "lodash";
-import NumberFormat from "react-number-format";
-import ButtonWithSpinner from "../ButtonWithSpinner";
-import { i18n } from "../../translate/i18n";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    width: "100%",
-  },
-  fullWidth: {
-    width: "100%",
-  },
-  textfield: {
-    width: "100%",
-  },
-  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),
-  },
-}));
-
-function SchedulesForm(props) {
-  const { initialValues, onSubmit, loading, labelSaveButton } = props;
-  const classes = useStyles();
-
-  const [schedules, setSchedules] = useState([
-    { weekday: "Segunda-feira", weekdayEn: "monday", startTime: "", endTime: "", },
-    { weekday: "Terça-feira", weekdayEn: "tuesday", startTime: "", endTime: "", },
-    { weekday: "Quarta-feira", weekdayEn: "wednesday", startTime: "", endTime: "", },
-    { weekday: "Quinta-feira", weekdayEn: "thursday", startTime: "", endTime: "", },
-    { weekday: "Sexta-feira", weekdayEn: "friday", startTime: "", endTime: "" },
-    { weekday: "Sábado", weekdayEn: "saturday", startTime: "", endTime: "" },
-    { weekday: "Domingo", weekdayEn: "sunday", startTime: "", endTime: "" },
-  ]);
-
-  useEffect(() => {
-    if (isArray(initialValues) && initialValues.length > 0) {
-      setSchedules(initialValues);
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [initialValues]);
-
-  const handleSubmit = (data) => {
-    onSubmit(data);
-  };
-
-  return (
-    <Formik
-      enableReinitialize
-      className={classes.fullWidth}
-      initialValues={{ schedules }}
-      onSubmit={({ schedules }) =>
-        setTimeout(() => {
-          handleSubmit(schedules);
-        }, 500)
-      }
-    >
-      {({ values }) => (
-        <Form className={classes.fullWidth}>
-          <FieldArray
-            name="schedules"
-            render={(arrayHelpers) => (
-              <Grid spacing={4} container>
-                {values.schedules.map((item, index) => {
-                  return (
-                      <Container>
-                          <FastField
-                            as={TextField}
-                            label={i18n.t("settings.schedules.form.weekday")}
-                            name={`schedules[${index}].weekday`}
-                            disabled
-                            variant="outlined"
-                            style={{ marginRight: "3.2%", width: "30%" }}
-                            margin="dense"
-                          />
-                          <FastField
-                            name={`schedules[${index}].startTime`}
-                            >
-                            {({ field }) => (
-                              <NumberFormat
-                                label={i18n.t("settings.schedules.form.initialHour")}
-                                {...field}
-                                variant="outlined"
-                                margin="dense"
-                                customInput={TextField}
-                                format="##:##"
-                                style={{ marginRight: "3.2%", width: "30%" }}
-                              />
-                            )}
-                          </FastField>
-                          <FastField
-                            name={`schedules[${index}].endTime`}
-                            >
-                            {({ field }) => (
-                              <NumberFormat
-                                label={i18n.t("settings.schedules.form.finalHour")}
-                                {...field}
-                                variant="outlined"
-                                margin="dense"
-                                customInput={TextField}
-                                format="##:##"
-                                style={{ marginRight: "3.2%", width: "30%" }}
-                              />
-                            )}
-                          </FastField>
-
-                      </Container>
-
-                  );
-                })}
-              </Grid>
-            )}
-          ></FieldArray>
-          <div style={{ textAlign: "center", marginTop: "2%" }} className={classes.buttonContainer}>
-            <ButtonWithSpinner
-              loading={loading}
-              type="submit"
-              color="primary"
-              variant="contained"
-            >
-              {labelSaveButton ?? i18n.t("settings.schedules.form.save")}
-            </ButtonWithSpinner>
-          </div>
-        </Form>
-      )}
-    </Formik>
-  );
-}
-
-export default SchedulesForm;

+ 0 - 727
frontend/src/components/Settings/Options.js

@@ -1,727 +0,0 @@
-import React, { useEffect, useState } from "react";
-
-import Grid from "@material-ui/core/Grid";
-import MenuItem from "@material-ui/core/MenuItem";
-import FormControl from "@material-ui/core/FormControl";
-import InputLabel from "@material-ui/core/InputLabel";
-import Select from "@material-ui/core/Select";
-import FormHelperText from "@material-ui/core/FormHelperText";
-import TextField from "@material-ui/core/TextField";
-import Title from "../Title";
-import Paper from "@material-ui/core/Paper";
-import Typography from "@material-ui/core/Typography";
-import useSettings from "../../hooks/useSettings";
-import { ToastContainer, toast } from 'react-toastify';
-import { makeStyles } from "@material-ui/core/styles";
-import { grey, blue } from "@material-ui/core/colors";
-import { Tabs, Tab } from "@material-ui/core";
-import { i18n } from "../../translate/i18n";
-
-//import 'react-toastify/dist/ReactToastify.css';
- 
-const useStyles = makeStyles((theme) => ({
-  container: {
-    paddingTop: theme.spacing(4),
-    paddingBottom: theme.spacing(4),
-  },
-  fixedHeightPaper: {
-    padding: theme.spacing(2),
-    display: "flex",
-    overflow: "auto",
-    flexDirection: "column",
-    height: 240,
-  },
-  tab: {
-    backgroundColor: theme.palette.options,  //DARK MODE PLW DESIGN//
-    borderRadius: 4,
-    width: "100%",
-    "& .MuiTab-wrapper": {
-      color: theme.palette.fontecor,
-    },   //DARK MODE PLW DESIGN//
-    "& .MuiTabs-flexContainer": {
-      justifyContent: "center"
-    }
-
-
-  },
-  paper: {
-    padding: theme.spacing(2),
-    display: "flex",
-    alignItems: "center",
-    marginBottom: 12,
-    width: "100%",
-  },
-  cardAvatar: {
-    fontSize: "55px",
-    color: grey[500],
-    backgroundColor: "#ffffff",
-    width: theme.spacing(7),
-    height: theme.spacing(7),
-  },
-  cardTitle: {
-    fontSize: "18px",
-    color: blue[700],
-  },
-  cardSubtitle: {
-    color: grey[600],
-    fontSize: "14px",
-  },
-  alignRight: {
-    textAlign: "right",
-  },
-  fullWidth: {
-    width: "100%",
-  },
-  selectContainer: {
-    width: "100%",
-    textAlign: "left",
-  },
-}));
-
-export default function Options(props) {
-  const { settings, scheduleTypeChanged } = props;
-  const classes = useStyles();
-  const [userRating, setUserRating] = useState("disabled");
-  const [scheduleType, setScheduleType] = useState("disabled");
-  const [callType, setCallType] = useState("enabled");
-  const [chatbotType, setChatbotType] = useState("");
-  const [CheckMsgIsGroup, setCheckMsgIsGroupType] = useState("enabled");
-
-  const [loadingUserRating, setLoadingUserRating] = useState(false);
-  const [loadingScheduleType, setLoadingScheduleType] = useState(false);
-  const [loadingCallType, setLoadingCallType] = useState(false);
-  const [loadingChatbotType, setLoadingChatbotType] = useState(false);
-  const [loadingCheckMsgIsGroup, setCheckMsgIsGroup] = useState(false);
-
-
-  //const [ipixcType, setIpIxcType] = useState("");
-  //const [loadingIpIxcType, setLoadingIpIxcType] = useState(false);
-  //const [tokenixcType, setTokenIxcType] = useState("");
-  //const [loadingTokenIxcType, setLoadingTokenIxcType] = useState(false);
-
-  //const [ipmkauthType, setIpMkauthType] = useState("");
-  //const [loadingIpMkauthType, setLoadingIpMkauthType] = useState(false);
-  //const [clientidmkauthType, setClientIdMkauthType] = useState("");
-  //const [loadingClientIdMkauthType, setLoadingClientIdMkauthType] = useState(false);
-  //const [clientsecretmkauthType, setClientSecrectMkauthType] = useState("");
-  //const [loadingClientSecrectMkauthType, setLoadingClientSecrectMkauthType] = useState(false);
-
-  const [asaasType, setAsaasType] = useState("");
-  const [loadingAsaasType, setLoadingAsaasType] = useState(false);
-  
-  // recursos a mais da plw design
-
-  const [SendGreetingAccepted, setSendGreetingAccepted] = useState("disabled");
-  const [loadingSendGreetingAccepted, setLoadingSendGreetingAccepted] = useState(false);
-  
-  const [SettingsTransfTicket, setSettingsTransfTicket] = useState("disabled");
-  const [loadingSettingsTransfTicket, setLoadingSettingsTransfTicket] = useState(false);
-  
-  const [sendGreetingMessageOneQueues, setSendGreetingMessageOneQueues] = useState("disabled");
-  const [loadingSendGreetingMessageOneQueues, setLoadingSendGreetingMessageOneQueues] = useState(false);
-
-  const { update } = useSettings();
-
-  useEffect(() => {
-    if (Array.isArray(settings) && settings.length) {
-      const userRating = settings.find((s) => s.key === "userRating");
-      if (userRating) {
-        setUserRating(userRating.value);
-      }
-      const scheduleType = settings.find((s) => s.key === "scheduleType");
-      if (scheduleType) {
-        setScheduleType(scheduleType.value);
-      }
-      const callType = settings.find((s) => s.key === "call");
-      if (callType) {
-        setCallType(callType.value);
-      }
-      const CheckMsgIsGroup = settings.find((s) => s.key === "CheckMsgIsGroup");
-      if (CheckMsgIsGroup) {
-        setCheckMsgIsGroupType(CheckMsgIsGroup.value);
-      }
-	  
-	  {/*PLW DESIGN SAUDAÇÃO*/}
-      const SendGreetingAccepted = settings.find((s) => s.key === "sendGreetingAccepted");
-      if (SendGreetingAccepted) {
-        setSendGreetingAccepted(SendGreetingAccepted.value);
-      }	 
-	  {/*PLW DESIGN SAUDAÇÃO*/}	 
-	  
-	  {/*TRANSFERIR TICKET*/}	
-	  const SettingsTransfTicket = settings.find((s) => s.key === "sendMsgTransfTicket");
-      if (SettingsTransfTicket) {
-        setSettingsTransfTicket(SettingsTransfTicket.value);
-      }
-	  {/*TRANSFERIR TICKET*/}
-
-      const sendGreetingMessageOneQueues = settings.find((s) => s.key === "sendGreetingMessageOneQueues");
-      if (sendGreetingMessageOneQueues) {
-        setSendGreetingMessageOneQueues(sendGreetingMessageOneQueues.value)
-      }	  
-	  
-      const chatbotType = settings.find((s) => s.key === "chatBotType");
-      if (chatbotType) {
-        setChatbotType(chatbotType.value);
-      }
-
-	    {/*const ipixcType = settings.find((s) => s.key === "ipixc");
-      if (ipixcType) {
-        setIpIxcType(ipixcType.value);
-      }*/}
-
-      {/*const tokenixcType = settings.find((s) => s.key === "tokenixc");
-      if (tokenixcType) {
-        setTokenIxcType(tokenixcType.value);
-      }*/}
-
-      {/*const ipmkauthType = settings.find((s) => s.key === "ipmkauth");
-      if (ipmkauthType) {
-        setIpMkauthType(ipmkauthType.value);
-      }*/}
-
-     {/* const clientidmkauthType = settings.find((s) => s.key === "clientidmkauth");
-      if (clientidmkauthType) {
-        setClientIdMkauthType(clientidmkauthType.value);
-      }*/}
-
-      {/*const clientsecretmkauthType = settings.find((s) => s.key === "clientsecretmkauth");
-      if (clientsecretmkauthType) {
-        setClientSecrectMkauthType(clientsecretmkauthType.value);
-      }*/}
-
-      const asaasType = settings.find((s) => s.key === "asaas");
-      if (asaasType) {
-        setAsaasType(asaasType.value);
-      }
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [settings]);
-
-  async function handleChangeUserRating(value) {
-    setUserRating(value);
-    setLoadingUserRating(true);
-    await update({
-      key: "userRating",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingUserRating(false);
-  }
-  
-    async function handleSendGreetingMessageOneQueues(value) {
-    setSendGreetingMessageOneQueues(value);
-    setLoadingSendGreetingMessageOneQueues(true);
-    await update({
-      key: "sendGreetingMessageOneQueues",
-      value,
-    });
-	toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingSendGreetingMessageOneQueues(false);
-  }
-
-  async function handleScheduleType(value) {
-    setScheduleType(value);
-    setLoadingScheduleType(true);
-    await update({
-      key: "scheduleType",
-      value,
-    });
-    //toast.success("Oraçãpeo atualizada com sucesso.");
-    toast.success(i18n.t("settings.options.toasts.success"), {
-      position: "top-right",
-      autoClose: 2000,
-      hideProgressBar: false,
-      closeOnClick: true,
-      pauseOnHover: false,
-      draggable: true,
-      theme: "light",
-      });
-    setLoadingScheduleType(false);
-    if (typeof scheduleTypeChanged === "function") {
-      scheduleTypeChanged(value);
-    }
-  }
-
-  async function handleCallType(value) {
-    setCallType(value);
-    setLoadingCallType(true);
-    await update({
-      key: "call",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingCallType(false);
-  }
-
-  async function handleChatbotType(value) {
-    setChatbotType(value);
-    setLoadingChatbotType(true);
-    await update({
-      key: "chatBotType",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingChatbotType(false);
-  }
-
-  async function handleGroupType(value) {
-    setCheckMsgIsGroupType(value);
-    setCheckMsgIsGroup(true);
-    await update({
-      key: "CheckMsgIsGroup",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setCheckMsgIsGroupType(false);
-    /*     if (typeof scheduleTypeChanged === "function") {
-          scheduleTypeChanged(value);
-        } */
-  }
-  
-  {/*NOVO CÓDIGO*/}  
-  async function handleSendGreetingAccepted(value) {
-    setSendGreetingAccepted(value);
-    setLoadingSendGreetingAccepted(true);
-    await update({
-      key: "sendGreetingAccepted",
-      value,
-    });
-	toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingSendGreetingAccepted(false);
-  }  
-  
-  
-  {/*NOVO CÓDIGO*/}    
-
-  async function handleSettingsTransfTicket(value) {
-    setSettingsTransfTicket(value);
-    setLoadingSettingsTransfTicket(true);
-    await update({
-      key: "sendMsgTransfTicket",
-      value,
-    });
-
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingSettingsTransfTicket(false);
-  } 
- 
- {/*async function handleChangeIPIxc(value) {
-    setIpIxcType(value);
-    setLoadingIpIxcType(true);
-    await update({
-      key: "ipixc",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingIpIxcType(false);
-  }
-
-   {/*async function handleChangeTokenIxc(value) {
-    setTokenIxcType(value);
-    setLoadingTokenIxcType(true);
-    await update({
-      key: "tokenixc",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingTokenIxcType(false);
-  }
-
-  async function handleChangeIpMkauth(value) {
-    setIpMkauthType(value);
-    setLoadingIpMkauthType(true);
-    await update({
-      key: "ipmkauth",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingIpMkauthType(false);
-  }
-
-  async function handleChangeClientIdMkauth(value) {
-    setClientIdMkauthType(value);
-    setLoadingClientIdMkauthType(true);
-    await update({
-      key: "clientidmkauth",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingClientIdMkauthType(false);
-  }
-
-  async function handleChangeClientSecrectMkauth(value) {
-    setClientSecrectMkauthType(value);
-    setLoadingClientSecrectMkauthType(true);
-    await update({
-      key: "clientsecretmkauth",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingClientSecrectMkauthType(false);
-  }*/}
-
-  async function handleChangeAsaas(value) {
-    setAsaasType(value);
-    setLoadingAsaasType(true);
-    await update({
-      key: "asaas",
-      value,
-    });
-    toast.success(i18n.t("settings.options.toasts.success"));
-    setLoadingAsaasType(false);
-  }
-  return (
-    <>
-      <Grid spacing={3} container>
-        {/* <Grid xs={12} item>
-                    <Title>Configurações Gerais</Title>
-                </Grid> */}
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="ratings-label">{i18n.t("settings.options.fields.ratings.title")}</InputLabel>
-            <Select
-              labelId="ratings-label"
-              value={userRating}
-              onChange={async (e) => {
-                handleChangeUserRating(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.ratings.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.ratings.enabled")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingUserRating && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="schedule-type-label">
-              {i18n.t("settings.options.fields.expedientManager.title")}
-            </InputLabel>
-            <Select
-              labelId="schedule-type-label"
-              value={scheduleType}
-              onChange={async (e) => {
-                handleScheduleType(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.disabled")}</MenuItem>
-              <MenuItem value={"queue"}>{i18n.t("settings.options.fields.expedientManager.queue")}</MenuItem>
-              <MenuItem value={"company"}>{i18n.t("settings.options.fields.expedientManager.company")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingScheduleType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="group-type-label">
-              {i18n.t("settings.options.fields.ignoreMessages.title")}
-            </InputLabel>
-            <Select
-              labelId="group-type-label"
-              value={CheckMsgIsGroup}
-              onChange={async (e) => {
-                handleGroupType(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.active")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingScheduleType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="call-type-label">
-              {i18n.t("settings.options.fields.acceptCall.title")}
-            </InputLabel>
-            <Select
-              labelId="call-type-label"
-              value={callType}
-              onChange={async (e) => {
-                handleCallType(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.acceptCall.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.acceptCall.enabled")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingCallType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="chatbot-type-label">
-              {i18n.t("settings.options.fields.chatbotType.title")}
-            </InputLabel>
-            <Select
-              labelId="chatbot-type-label"
-              value={chatbotType}
-              onChange={async (e) => {
-                handleChatbotType(e.target.value);
-              }}
-            >
-              <MenuItem value={"text"}>{i18n.t("settings.options.fields.chatbotType.text")}</MenuItem>
-			 {/*<MenuItem value={"button"}>Botão</MenuItem>*/}
-             {/*<MenuItem value={"list"}>Lista</MenuItem>*/}
-            </Select>
-            <FormHelperText>
-              {loadingChatbotType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-		{/* ENVIAR SAUDAÇÃO AO ACEITAR O TICKET */}
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="sendGreetingAccepted-label">
-              {i18n.t("settings.options.fields.sendGreetingAccepted.title")}
-            </InputLabel>
-            <Select
-              labelId="sendGreetingAccepted-label"
-              value={SendGreetingAccepted}
-              onChange={async (e) => {
-                handleSendGreetingAccepted(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.enabled")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingSendGreetingAccepted && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-		{/* ENVIAR SAUDAÇÃO AO ACEITAR O TICKET */}
-		
-		{/* ENVIAR MENSAGEM DE TRANSFERENCIA DE SETOR/ATENDENTE */}
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="sendMsgTransfTicket-label">
-              {i18n.t("settings.options.fields.sendMsgTransfTicket.title")}
-            </InputLabel>
-            <Select
-              labelId="sendMsgTransfTicket-label"
-              value={SettingsTransfTicket}
-              onChange={async (e) => {
-                handleSettingsTransfTicket(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.enabled")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingSettingsTransfTicket && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-		
-		{/* ENVIAR SAUDAÇÃO QUANDO HOUVER SOMENTE 1 FILA */}
-        <Grid xs={12} sm={6} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <InputLabel id="sendGreetingMessageOneQueues-label">
-              {i18n.t("settings.options.fields.sendGreetingMessageOneQueues.title")}
-            </InputLabel>
-            <Select
-              labelId="sendGreetingMessageOneQueues-label"
-              value={sendGreetingMessageOneQueues}
-              onChange={async (e) => {
-                handleSendGreetingMessageOneQueues(e.target.value);
-              }}
-            >
-              <MenuItem value={"disabled"}>{i18n.t("settings.options.fields.disabled")}</MenuItem>
-              <MenuItem value={"enabled"}>{i18n.t("settings.options.fields.enabled")}</MenuItem>
-            </Select>
-            <FormHelperText>
-              {loadingSendGreetingMessageOneQueues && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-		
-      </Grid>
-      <Grid spacing={3} container>
-        <Tabs
-          indicatorColor="primary"
-          textColor="primary"
-          scrollButtons="on"
-          variant="scrollable"
-          className={classes.tab}
-          style={{
-            marginBottom: 20,
-            marginTop: 20
-          }}
-        >
-          <Tab
-
-            label={i18n.t("settings.options.tabs.integrations")} />
-
-        </Tabs>
-
-      </Grid>
-      {/*-----------------IXC DESATIVADO 4.6.5-----------------*/}
-      {/*<Grid spacing={3} container
-        style={{ marginBottom: 10 }}>
-        <Tabs
-          indicatorColor="primary"
-          textColor="primary"
-          scrollButtons="on"
-          variant="scrollable"
-          className={classes.tab}
-        >
-          <Tab
-
-            label="IXC" />
-
-        </Tabs>
-        <Grid xs={12} sm={6} md={6} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="ipixc"
-              name="ipixc"
-              margin="dense"
-              label="IP do IXC"
-              variant="outlined"
-              value={ipixcType}
-              onChange={async (e) => {
-                handleChangeIPIxc(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingIpIxcType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={6} md={6} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="tokenixc"
-              name="tokenixc"
-              margin="dense"
-              label="Token do IXC"
-              variant="outlined"
-              value={tokenixcType}
-              onChange={async (e) => {
-                handleChangeTokenIxc(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingTokenIxcType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-      </Grid>*/}
-      {/*-----------------MK-AUTH DESATIVADO 4.6.5-----------------*/}
-      {/*<Grid spacing={3} container
-        style={{ marginBottom: 10 }}>
-        <Tabs
-          indicatorColor="primary"
-          textColor="primary"
-          scrollButtons="on"
-          variant="scrollable"
-          className={classes.tab}
-        >
-          <Tab label="MK-AUTH" />
-
-        </Tabs>
-        <Grid xs={12} sm={12} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="ipmkauth"
-              name="ipmkauth"
-              margin="dense"
-              label="Ip Mk-Auth"
-              variant="outlined"
-              value={ipmkauthType}
-              onChange={async (e) => {
-                handleChangeIpMkauth(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingIpMkauthType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={12} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="clientidmkauth"
-              name="clientidmkauth"
-              margin="dense"
-              label="Client Id"
-              variant="outlined"
-              value={clientidmkauthType}
-              onChange={async (e) => {
-                handleChangeClientIdMkauth(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingClientIdMkauthType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-        <Grid xs={12} sm={12} md={4} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="clientsecretmkauth"
-              name="clientsecretmkauth"
-              margin="dense"
-              label="Client Secret"
-              variant="outlined"
-              value={clientsecretmkauthType}
-              onChange={async (e) => {
-                handleChangeClientSecrectMkauth(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingClientSecrectMkauthType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-      </Grid>*/}
-      {/*-----------------ASAAS-----------------*/}
-      <Grid spacing={3} container
-        style={{ marginBottom: 10 }}>
-        <Tabs
-          indicatorColor="primary"
-          textColor="primary"
-          scrollButtons="on"
-          variant="scrollable"
-          className={classes.tab}
-        >
-          <Tab label="ASAAS" />
-
-        </Tabs>
-        <Grid xs={12} sm={12} md={12} item>
-          <FormControl className={classes.selectContainer}>
-            <TextField
-              id="asaas"
-              name="asaas"
-              margin="dense"
-              label="Token Asaas"
-              variant="outlined"
-              value={asaasType}
-              onChange={async (e) => {
-                handleChangeAsaas(e.target.value);
-              }}
-            >
-            </TextField>
-            <FormHelperText>
-              {loadingAsaasType && i18n.t("settings.options.updating")}
-            </FormHelperText>
-          </FormControl>
-        </Grid>
-      </Grid>
-    </>
-  );
-}

+ 0 - 70
frontend/src/components/SubscriptionModal/index.js

@@ -1,70 +0,0 @@
-import React, { useEffect, useRef } from "react";
-
-
-import { makeStyles } from "@material-ui/core/styles";
-import { green } from "@material-ui/core/colors";
-import Dialog from "@material-ui/core/Dialog";
-import DialogContent from "@material-ui/core/DialogContent";
-import CheckoutPage from "../CheckoutPage/";
-
-const useStyles = makeStyles((theme) => ({
-  root: {
-    display: "flex",
-    flexWrap: "wrap",
-  },
-  textField: {
-    marginRight: theme.spacing(1),
-    flex: 1,
-  },
-
-  extraAttr: {
-    display: "flex",
-    justifyContent: "center",
-    alignItems: "center",
-  },
-
-  btnWrapper: {
-    position: "relative",
-  },
-
-  buttonProgress: {
-    color: green[500],
-    position: "absolute",
-    top: "50%",
-    left: "50%",
-    marginTop: -12,
-    marginLeft: -12,
-  },
-}));
-
-
-const ContactModal = ({ open, onClose, Invoice, contactId, initialValues, onSave }) => {
-  const classes = useStyles();
-  const isMounted = useRef(true);
-
-
-  useEffect(() => {
-    return () => {
-      isMounted.current = false;
-    };
-  }, []);
-
-
-  const handleClose = () => {
-    onClose();
-  };
-
-  return (
-    <div className={classes.root}>
-      <Dialog open={open} onClose={handleClose} maxWidth="md" scroll="paper">
-        <DialogContent dividers>
-          <CheckoutPage
-            Invoice={Invoice}
-          />
-        </DialogContent>
-      </Dialog>
-    </div>
-  );
-};
-
-export default ContactModal;

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است