From b62af011212424193c25eee4e36f902ff581bef6 Mon Sep 17 00:00:00 2001 From: Cody Gordon Date: Sun, 8 Oct 2023 17:33:04 -0700 Subject: [PATCH] bulk send batch progress UI --- .eslintrc | 8 +- package.json | 3 + .../AssignmentTexter/BulkSendButton.jsx | 162 +++++++++++++----- 3 files changed, 125 insertions(+), 48 deletions(-) diff --git a/.eslintrc b/.eslintrc index a6796f1ec..2f45ceb40 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,5 +1,11 @@ { "extends": ["airbnb", "prettier"], "parser": "@babel/eslint-parser", - "env": { "jest": true, "node": true, "browser": true, "jasmine": true } + "env": { "jest": true, "node": true, "browser": true, "jasmine": true }, + "rules": { + "no-console": [ + "warn", + { "allow": ["warn", "error", "info", "time", "timeEnd"] } + ] + } } diff --git a/package.json b/package.json index 98e05264d..f3a43d301 100644 --- a/package.json +++ b/package.json @@ -232,5 +232,8 @@ "react-tooltip": "^4.2.13", "recompose": "^0.30.0", "webpack-cli": "^4.7.2" + }, + "browser": { + "crypto": false } } diff --git a/src/components/AssignmentTexter/BulkSendButton.jsx b/src/components/AssignmentTexter/BulkSendButton.jsx index a73b22581..5ddca8660 100644 --- a/src/components/AssignmentTexter/BulkSendButton.jsx +++ b/src/components/AssignmentTexter/BulkSendButton.jsx @@ -1,73 +1,141 @@ import PropTypes from "prop-types"; -import React, { Component } from "react"; +import React, { useState, useEffect } from "react"; import { StyleSheet, css } from "aphrodite"; import Button from "@material-ui/core/Button"; - +import LinearProgress from "@material-ui/core/LinearProgress"; +import Typography from '@material-ui/core/Typography'; +import Snackbar from '@material-ui/core/Snackbar'; +import Alert from '@material-ui/lab/Alert'; + // This is because the Toolbar from material-ui seems to only apply the correct margins if the // immediate child is a Button or other type it recognizes. Can get rid of this if we remove material-ui const styles = StyleSheet.create({ container: { - display: "block", - width: "25ex", - marginLeft: "auto", - marginRight: "auto" + display: "flex", + flexFlow: "column", + alignItems: "center", + width: "30%", + maxWidth: 300, + height: "100%", + marginTop: 10, + marginRight: "auto", + marginLeft: "auto" + }, + progressContainer: { + width: "100%" + }, + progressText: { + position: "relative", + textAlign: "center", + color: "white" + }, + progressBarRoot: { + height: 10, + borderRadius: 5 } }); -export default class BulkSendButton extends Component { - state = { - isSending: false - }; +function BulkSendButton({ + assignment, setDisabled, bulkSendMessages, refreshData, onFinishContact +}) { + const totalChunkSize = window.BULK_SEND_CHUNK_SIZE; + const [isSending, setIsSending] = useState(false); + const [totalSentMessages, setTotalSentMessages] = useState(0); + const [progress, setProgress] = useState(0); + const [errorMessage, setErrorMessage] = useState(''); - sendMessages = async () => { - let sentMessages = 0; + const sendMessages = async () => { + try { + const { data } = await bulkSendMessages(assignment.id); + const sentMessages = data.bulkSendMessages.length; + const updatedTotalSent = totalSentMessages + sentMessages; - this.setState({ isSending: true }); - this.props.setDisabled(true); + if (!sentMessages) { + /* end sending if no messages were left to send */ + setProgress(100); + } else { + setTotalSentMessages(updatedTotalSent); + setProgress((updatedTotalSent / totalChunkSize) * 100); + } + } catch (err) { + console.error(err); + setErrorMessage(err.message); + } + } - console.log(`Start bulk sending messages ${new Date()}`); - while (sentMessages < window.BULK_SEND_CHUNK_SIZE) { - const res = await this.props.bulkSendMessages(this.props.assignment.id); + const handleEndSend = () => { + refreshData(); + setErrorMessage(''); + setIsSending(false); + setProgress(0); + setTotalSentMessages(0); + setDisabled(false); + onFinishContact(); + } - // Check if all messages have been sent - if (!res.data.bulkSendMessages.length) { - break; + useEffect(() => { + if (isSending) { + /* sendMessages will be called the first time when isSending is set to true + and only called again when the progress state is updated and not complete */ + if (progress < 100) { + sendMessages(); + } else { + /* display "sent all" message for half a sec */ + setTimeout(handleEndSend, 500); } - - // Print progress to console - sentMessages += res.data.bulkSendMessages.length; - console.log(`Bulk sent ${sentMessages} messages ${new Date()}`); } - this.props.refreshData(); - console.log(`Finish bulk sending messages ${new Date()}`); - - this.setState({ isSending: false }); - this.props.setDisabled(false); - this.props.onFinishContact(); - }; + }, [isSending, progress]); - render() { - return ( -
+ return ( +
+ {isSending ? ( +
+
+ + {progress === 100 + ? 'Sent all messages!' + : `Sent ${totalSentMessages} of ${totalChunkSize} messages...`} + +
+ +
+ ) : ( -
- ); - } + )} + + + {errorMessage} + + +
+ ); } BulkSendButton.propTypes = { - assignment: PropTypes.object, - onFinishContact: PropTypes.func, - bulkSendMessages: PropTypes.func, - refreshData: PropTypes.func, - setDisabled: PropTypes.func + assignment: PropTypes.shape({ id: PropTypes.number }).isRequired, + onFinishContact: PropTypes.func.isRequired, + bulkSendMessages: PropTypes.func.isRequired, + refreshData: PropTypes.func.isRequired, + setDisabled: PropTypes.func.isRequired }; + +export default BulkSendButton;