Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bulk Send Batch Progress UI #2305

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
Copy link
Collaborator Author

@codygordon codygordon Oct 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: removed this because it was fixed a different way in another PR; confirmed that other fix works for me locally.

}
}
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;