From b51c7904e0d30367ad01968cf6b9500700ff6a52 Mon Sep 17 00:00:00 2001 From: canove Date: Tue, 20 Oct 2020 21:29:45 -0300 Subject: [PATCH] feat: add contact option on ticket creation modal --- frontend/src/components/ContactModal/index.js | 27 ++- .../src/components/NewTicketModal/index.js | 198 +++++++++++------- frontend/src/translate/languages/en.js | 2 +- frontend/src/translate/languages/es.js | 2 +- frontend/src/translate/languages/pt.js | 2 +- 5 files changed, 151 insertions(+), 80 deletions(-) diff --git a/frontend/src/components/ContactModal/index.js b/frontend/src/components/ContactModal/index.js index 5b4264b..93aff6e 100644 --- a/frontend/src/components/ContactModal/index.js +++ b/frontend/src/components/ContactModal/index.js @@ -63,7 +63,7 @@ const ContactSchema = Yup.object().shape({ email: Yup.string().email("Invalid email"), }); -const ContactModal = ({ open, onClose, contactId }) => { +const ContactModal = ({ open, onClose, contactId, initialValues, onSave }) => { const classes = useStyles(); const isMounted = useRef(true); @@ -83,7 +83,14 @@ const ContactModal = ({ open, onClose, contactId }) => { 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) { @@ -104,10 +111,14 @@ const ContactModal = ({ open, onClose, contactId }) => { }; fetchContact(); - }, [contactId, open]); + }, [contactId, open, initialValues]); - const handleClose = () => { - onClose(); + const handleClose = contactId => { + if (contactId) { + onClose(contactId); + } else { + onClose(); + } setContact(initialState); }; @@ -115,8 +126,13 @@ const ContactModal = ({ open, onClose, contactId }) => { try { if (contactId) { await api.put(`/contacts/${contactId}`, values); + handleClose(); } else { - await api.post("/contacts", values); + const { data } = await api.post("/contacts", values); + if (onSave) { + onSave(data); + } + handleClose(); } toast.success(i18n.t("contactModal.success")); } catch (err) { @@ -131,7 +147,6 @@ const ContactModal = ({ open, onClose, contactId }) => { toast.error("Unknown error"); } } - handleClose(); }; return ( diff --git a/frontend/src/components/NewTicketModal/index.js b/frontend/src/components/NewTicketModal/index.js index bfab47c..4b77639 100644 --- a/frontend/src/components/NewTicketModal/index.js +++ b/frontend/src/components/NewTicketModal/index.js @@ -19,6 +19,7 @@ import { makeStyles } from "@material-ui/core/styles"; import { i18n } from "../../translate/i18n"; import api from "../../services/api"; import ButtonWithSpinner from "../ButtonWithSpinner"; +import ContactModal from "../ContactModal"; const useStyles = makeStyles(theme => ({ root: { @@ -27,7 +28,7 @@ const useStyles = makeStyles(theme => ({ }, })); -const filterOptions = createFilterOptions({ +const filter = createFilterOptions({ trim: true, }); @@ -40,9 +41,14 @@ const NewTicketModal = ({ modalOpen, onClose }) => { const [loading, setLoading] = useState(false); const [searchParam, setSearchParam] = useState(""); const [selectedContact, setSelectedContact] = useState(null); + const [newContact, setNewContact] = useState({}); + const [contactModalOpen, setContactModalOpen] = useState(false); useEffect(() => { - if (!modalOpen || searchParam.length < 3) return; + if (!modalOpen || searchParam.length < 3) { + setLoading(false); + return; + } setLoading(true); const delayDebounceFn = setTimeout(() => { const fetchContacts = async () => { @@ -53,6 +59,7 @@ const NewTicketModal = ({ modalOpen, onClose }) => { setOptions(data.contacts); setLoading(false); } catch (err) { + setLoading(false); const errorMsg = err.response?.data?.error; if (errorMsg) { if (i18n.exists(`backendErrors.${errorMsg}`)) { @@ -77,13 +84,12 @@ const NewTicketModal = ({ modalOpen, onClose }) => { setSelectedContact(null); }; - const handleSaveTicket = async e => { - e.preventDefault(); - if (!selectedContact) return; + const handleSaveTicket = async contactId => { + if (!contactId) return; setLoading(true); try { const { data: ticket } = await api.post("/tickets", { - contactId: selectedContact.id, + contactId: contactId, userId: userId, status: "open", }); @@ -104,73 +110,123 @@ const NewTicketModal = ({ modalOpen, onClose }) => { handleClose(); }; + 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 = (options, params) => { + const filtered = filter(options, params); + + if (params.inputValue !== "" && !loading && searchParam.length >= 3) { + filtered.push({ + name: `${params.inputValue}`, + }); + } + + return filtered; + }; + + const renderOption = option => { + if (option.number) { + return `${option.name} - ${option.number}`; + } else { + return `${i18n.t("newTicketModal.add")} ${option.name}`; + } + }; + + const renderOptionLabel = option => { + if (option.number) { + return `${option.name} - ${option.number}`; + } else { + return `${option.name}`; + } + }; + return (
- -
- - {i18n.t("newTicketModal.title")} - - - `${option.name} - ${option.number}`} - onChange={(e, newValue) => { - setSelectedContact(newValue); - }} - options={options} - filterOptions={filterOptions} - noOptionsText={i18n.t("newTicketModal.noOptions")} - loading={loading} - renderInput={params => ( - setSearchParam(e.target.value)} - id="my-input" - InputProps={{ - ...params.InputProps, - endAdornment: ( - - {loading ? ( - - ) : null} - {params.InputProps.endAdornment} - - ), - }} - /> - )} - /> - - - - - {i18n.t("newTicketModal.buttons.ok")} - - -
+ + + + {i18n.t("newTicketModal.title")} + + + handleSelectOption(e, newValue)} + renderInput={params => ( + setSearchParam(e.target.value)} + onKeyPress={e => { + if (loading || !selectedContact) return; + else if (e.key === "Enter") { + handleSaveTicket(selectedContact.id); + } + }} + InputProps={{ + ...params.InputProps, + endAdornment: ( + + {loading ? ( + + ) : null} + {params.InputProps.endAdornment} + + ), + }} + /> + )} + /> + + + + handleSaveTicket(selectedContact.id)} + color="primary" + loading={loading} + > + {i18n.t("newTicketModal.buttons.ok")} + +
); diff --git a/frontend/src/translate/languages/en.js b/frontend/src/translate/languages/en.js index f0172dd..4aad66c 100644 --- a/frontend/src/translate/languages/en.js +++ b/frontend/src/translate/languages/en.js @@ -177,7 +177,7 @@ const messages = { newTicketModal: { title: "Create Ticket", fieldLabel: "Type to search for a contact", - noOptions: "No contacts found. Try another name.", + add: "Add", buttons: { ok: "Save", cancel: "Cancel", diff --git a/frontend/src/translate/languages/es.js b/frontend/src/translate/languages/es.js index 887bb82..5c7e6fd 100644 --- a/frontend/src/translate/languages/es.js +++ b/frontend/src/translate/languages/es.js @@ -181,7 +181,7 @@ const messages = { newTicketModal: { title: "Crear Ticket", fieldLabel: "Escribe para buscar un contacto", - noOptions: "No se encontraron contactos. Prueba con otro nombre.", + add: "AƱadir", buttons: { ok: "Guardar", cancel: "Cancelar", diff --git a/frontend/src/translate/languages/pt.js b/frontend/src/translate/languages/pt.js index bd1eac8..41a32da 100644 --- a/frontend/src/translate/languages/pt.js +++ b/frontend/src/translate/languages/pt.js @@ -178,7 +178,7 @@ const messages = { newTicketModal: { title: "Criar Ticket", fieldLabel: "Digite para pesquisar o contato", - noOptions: "Nenhum contato encontrado. Tente outro nome.", + add: "Adicionar", buttons: { ok: "Salvar", cancel: "Cancelar",