diff --git a/frontend/src/components/ButtonWithSpinner/index.js b/frontend/src/components/ButtonWithSpinner/index.js new file mode 100644 index 0000000..542c39c --- /dev/null +++ b/frontend/src/components/ButtonWithSpinner/index.js @@ -0,0 +1,35 @@ +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 ( + + ); +}; + +export default ButtonWithSpinner; diff --git a/frontend/src/components/MessageInput/index.js b/frontend/src/components/MessageInput/index.js index 3d688d6..97647a8 100644 --- a/frontend/src/components/MessageInput/index.js +++ b/frontend/src/components/MessageInput/index.js @@ -195,55 +195,54 @@ const MessageInput = ({ ticketStatus }) => { setLoading(false); }; - const handleStartRecording = () => { - navigator.getUserMedia( - { audio: true }, - () => { - Mp3Recorder.start() - .then(() => { - setRecording(true); - }) - .catch(e => console.error(e)); - }, - () => { - console.log("Permission Denied"); - } - ); - }; - - const handleUploadAudio = () => { + const handleStartRecording = async () => { setLoading(true); - Mp3Recorder.stop() - .getMp3() - .then(async ([buffer, blob]) => { - if (blob.size < 10000) { - setLoading(false); - setRecording(false); - return; - } - const formData = new FormData(); - const filename = `${new Date().getTime()}.mp3`; - formData.append("media", blob, filename); - formData.append("body", filename); - formData.append("fromMe", true); - try { - await api.post(`/messages/${ticketId}`, formData); - } catch (err) { - console.log(err); - if (err.response && err.response.data && err.response.data.error) { - toast.error(err.response.data.error); - } - } - setRecording(false); - setLoading(false); - }) - .catch(err => console.log(err)); + try { + await navigator.mediaDevices.getUserMedia({ audio: true }); + await Mp3Recorder.start(); + setRecording(true); + setLoading(false); + } catch (err) { + console.log(err); + setLoading(false); + } }; - const handleCancelAudio = () => { - Mp3Recorder.stop() - .getMp3() - .then(() => setRecording(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("media", blob, filename); + formData.append("body", filename); + formData.append("fromMe", true); + + await api.post(`/messages/${ticketId}`, formData); + + setRecording(false); + setLoading(false); + } catch (err) { + console.log(err); + if (err.response && err.response.data && err.response.data.error) { + toast.error(err.response.data.error); + } + } + }; + + const handleCancelAudio = async () => { + try { + await Mp3Recorder.stop().getMp3(); + setRecording(false); + } catch (err) { + console.log(err); + } }; if (media.preview) diff --git a/frontend/src/components/NewTicketModal/index.js b/frontend/src/components/NewTicketModal/index.js index db8b060..6bb2c09 100644 --- a/frontend/src/components/NewTicketModal/index.js +++ b/frontend/src/components/NewTicketModal/index.js @@ -13,12 +13,12 @@ import Autocomplete, { createFilterOptions, } from "@material-ui/lab/Autocomplete"; import CircularProgress from "@material-ui/core/CircularProgress"; -import { green } from "@material-ui/core/colors"; import { makeStyles } from "@material-ui/core/styles"; import { i18n } from "../../translate/i18n"; import api from "../../services/api"; +import ButtonWithSpinner from "../ButtonWithSpinner"; const useStyles = makeStyles(theme => ({ root: { @@ -26,19 +26,11 @@ const useStyles = makeStyles(theme => ({ flexWrap: "wrap", }, - btnWrapper: { - // margin: theme.spacing(1), - position: "relative", - }, - - buttonProgress: { - color: green[500], - position: "absolute", - top: "50%", - left: "50%", - marginTop: -12, - marginLeft: -12, - }, + // btnWrapper: { + // // margin: theme.spacing(1), + // // position: "relative", + // display: "flex", + // }, })); const filterOptions = createFilterOptions({ @@ -163,21 +155,14 @@ const NewTicketModal = ({ modalOpen, onClose }) => { > {i18n.t("newTicketModal.buttons.cancel")} - + diff --git a/frontend/src/components/TicketActionButtons/index.js b/frontend/src/components/TicketActionButtons/index.js index e4ccca6..d17515c 100644 --- a/frontend/src/components/TicketActionButtons/index.js +++ b/frontend/src/components/TicketActionButtons/index.js @@ -3,12 +3,13 @@ import { useHistory } from "react-router-dom"; import { toast } from "react-toastify"; import { makeStyles } from "@material-ui/core/styles"; -import { Button, IconButton } from "@material-ui/core"; +import { IconButton } from "@material-ui/core"; import { MoreVert, Replay } from "@material-ui/icons"; import { i18n } from "../../translate/i18n"; import api from "../../services/api"; import TicketOptionsMenu from "../TicketOptionsMenu"; +import ButtonWithSpinner from "../ButtonWithSpinner"; const useStyles = makeStyles(theme => ({ actionButtons: { @@ -27,6 +28,7 @@ const TicketActionButtons = ({ ticket }) => { const history = useHistory(); const userId = +localStorage.getItem("userId"); const [anchorEl, setAnchorEl] = useState(null); + const [loading, setLoading] = useState(false); const ticketOptionsMenuOpen = Boolean(anchorEl); const handleOpenTicketOptionsMenu = e => { @@ -38,18 +40,21 @@ const TicketActionButtons = ({ ticket }) => { }; const handleUpdateTicketStatus = async (e, status, userId) => { + setLoading(true); try { await api.put(`/tickets/${ticket.id}`, { status: status, userId: userId || null, }); + setLoading(false); if (status === "open") { history.push(`/tickets/${ticket.id}`); } else { history.push("/tickets"); } } catch (err) { + setLoading(false); console.log(err); if (err.response && err.response.data && err.response.data.error) { toast.error(err.response.data.error); @@ -60,31 +65,34 @@ const TicketActionButtons = ({ ticket }) => { return (
{ticket.status === "closed" && ( - + )} {ticket.status === "open" && ( <> - - + @@ -97,14 +105,15 @@ const TicketActionButtons = ({ ticket }) => { )} {ticket.status === "pending" && ( - + )}
); diff --git a/frontend/src/components/TicketHeader/index.js b/frontend/src/components/TicketHeader/index.js index 8725042..d05c296 100644 --- a/frontend/src/components/TicketHeader/index.js +++ b/frontend/src/components/TicketHeader/index.js @@ -16,12 +16,16 @@ const useStyles = makeStyles(theme => ({ const TicketHeader = ({ loading, children }) => { const classes = useStyles(); - if (loading) return ; - return ( - - {children} - + <> + {loading ? ( + + ) : ( + + {children} + + )} + ); }; diff --git a/frontend/src/components/TicketListItem/index.js b/frontend/src/components/TicketListItem/index.js index 4457d66..efe818f 100644 --- a/frontend/src/components/TicketListItem/index.js +++ b/frontend/src/components/TicketListItem/index.js @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState, useEffect, useRef } from "react"; import { useHistory, useParams } from "react-router-dom"; import { parseISO, format, isSameDay } from "date-fns"; @@ -12,23 +12,15 @@ import Typography from "@material-ui/core/Typography"; import Avatar from "@material-ui/core/Avatar"; import Divider from "@material-ui/core/Divider"; import Badge from "@material-ui/core/Badge"; -import Button from "@material-ui/core/Button"; import { i18n } from "../../translate/i18n"; import api from "../../services/api"; +import ButtonWithSpinner from "../ButtonWithSpinner"; const useStyles = makeStyles(theme => ({ ticket: { position: "relative", - "& .hidden-button": { - display: "none", - }, - "&:hover .hidden-button": { - display: "flex", - position: "absolute", - left: "50%", - }, }, noTicketsDiv: { display: "flex", @@ -83,23 +75,41 @@ const useStyles = makeStyles(theme => ({ color: "white", backgroundColor: green[500], }, + + acceptButton: { + position: "absolute", + left: "50%", + }, })); const TicketListItem = ({ ticket }) => { const classes = useStyles(); const history = useHistory(); const userId = +localStorage.getItem("userId"); + const [loading, setLoading] = useState(false); const { ticketId } = useParams(); + const isMounted = useRef(true); + + useEffect(() => { + return () => { + isMounted.current = false; + }; + }, []); const handleAcepptTicket = async ticketId => { + setLoading(true); try { await api.put(`/tickets/${ticketId}`, { status: "open", userId: userId, }); } catch (err) { + setLoading(false); alert(err); } + if (isMounted.current) { + setLoading(false); + } history.push(`/tickets/${ticketId}`); }; @@ -180,17 +190,18 @@ const TicketListItem = ({ ticket }) => { } /> - {ticket.status === "pending" ? ( - - ) : null} + + )}