Skip to content

Commit

Permalink
bulk send batch progress UI
Browse files Browse the repository at this point in the history
  • Loading branch information
codygordon committed Oct 9, 2023
1 parent a0cd0d5 commit b62af01
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 48 deletions.
8 changes: 7 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -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"] }
]
}
}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -232,5 +232,8 @@
"react-tooltip": "^4.2.13",
"recompose": "^0.30.0",
"webpack-cli": "^4.7.2"
},
"browser": {
"crypto": false
}
}
162 changes: 115 additions & 47 deletions src/components/AssignmentTexter/BulkSendButton.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className={css(styles.container)}>
return (
<div className={css(styles.container)}>
{isSending ? (
<div className={css(styles.progressContainer)}>
<div className={css(styles.progressText)}>
<Typography variant="subtitle1">
{progress === 100
? 'Sent all messages!'
: `Sent ${totalSentMessages} of ${totalChunkSize} messages...`}
</Typography>
</div>
<LinearProgress
variant="determinate"
value={progress}
classes={{ root: css(styles.progressBarRoot) }}
/>
</div>
) : (
<Button
onClick={this.sendMessages}
disabled={this.state.isSending}
onClick={() => setIsSending(true)}
disabled={isSending}
color="primary"
variant="contained"
>
{this.state.isSending
? "Sending..."
: `Send Bulk (${window.BULK_SEND_CHUNK_SIZE})`}
{`Send Bulk (${totalChunkSize})`}
</Button>
</div>
);
}
)}
<Snackbar
anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
open={!!errorMessage}
autoHideDuration={6000}
onClose={handleEndSend}
>
<Alert
onClose={handleEndSend}
severity="error"
>
{errorMessage}
</Alert>
</Snackbar>
</div>
);
}

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;

0 comments on commit b62af01

Please sign in to comment.