feat: Add historical email content data to bulk course email task manager

[MICROBA-1621]

* Add table that displays info about previously sent bulk course email messages through our tool.
* Add modal to view the contents of previously sent messages.
* Extract strings to a dedicated `messages.js` file to help make the `BulkEmailContentHistory.jsx` file more readable.
This commit is contained in:
Justin Hynes
2022-01-11 13:20:16 -05:00
parent ab274d1ea9
commit 50747195bf
2 changed files with 299 additions and 21 deletions

View File

@@ -1,41 +1,241 @@
import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { useParams } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import {
Alert, Button, DataTable, Modal,
} from '@edx/paragon';
import messages from './messages';
import { getSentEmailHistory } from './api';
export default function BulkEmailContentHistory() {
export function BulkEmailContentHistory({ intl }) {
const { courseId } = useParams();
const [emailHistoryData, setEmailHistoryData] = useState(); // eslint-disable-line no-unused-vars
const [emailHistoryData, setEmailHistoryData] = useState();
const [errorRetrievingData, setErrorRetrievingData] = useState(false);
const [showHistoricalEmailContentTable, setShowHistoricalEmailContentTable] = useState(false);
const [isMessageModalOpen, setIsMessageModalOpen] = useState(false);
const [messageContent, setMessageContent] = useState();
useEffect(() => {
async function fetchSentEmailHistoryData() {
const data = await getSentEmailHistory(courseId);
/**
* Async function that makes a REST API call to retrieve historical email message data sent by the bulk course email
* tool from edx-platform.
*/
async function fetchSentEmailHistoryData() {
let data = null;
try {
data = await getSentEmailHistory(courseId);
} catch (error) {
setErrorRetrievingData(true);
}
if (data) {
const { emails } = data;
setEmailHistoryData(emails);
setShowHistoricalEmailContentTable(true);
}
fetchSentEmailHistoryData();
}, []);
}
/**
* This function is responsible for setting the current `messageContent` state data. This will be the contents of a
* previously sent email message from the bulk course email tool. This also toggles a modal to be visible to display
* the message contents to the end user.
*/
const onViewMessageClick = (tableData) => {
setMessageContent(tableData);
setIsMessageModalOpen(true);
};
/**
* Render function for the email content history table. If an error occurs while attempting to fetch data from
* edx-platform we will render this error instead of the table.
*/
const renderError = () => (
<div>
<Alert variant="danger">
<p className="font-weight-bold">
{intl.formatMessage(messages.errorFetchingData)}
</p>
</Alert>
</div>
);
/**
* Render function for the email content history table. If there is no data to display in our table we will render
* this informative message instead.
*/
const renderEmpty = () => (
<div className="pt-1">
<Alert variant="warning">
<p className="font-weight-bold">
{intl.formatMessage(messages.noEmailData)}
</p>
</Alert>
</div>
);
/**
* Renders a modal that will display the contents of a single historical email message sent via the bulk course email
* tool to a user.
*/
const renderMessageModal = () => (
<div>
<Modal
open={isMessageModalOpen}
title=""
body={(
<div>
<div className="d-flex flex-row">
<p>
{intl.formatMessage(messages.modalMessageSubject)}
</p>
<p className="pl-2">
{messageContent.subject}
</p>
</div>
<div className="d-flex flex-row">
<p>
{intl.formatMessage(messages.modalMessageSentBy)}
</p>
<p className="pl-2">
{messageContent.requester}
</p>
</div>
<div className="d-flex flex-row">
<p>
{intl.formatMessage(messages.modalMessageTimeSent)}
</p>
<p className="pl-2">
{messageContent.created}
</p>
</div>
<div className="d-flex flex-row">
<p>
{intl.formatMessage(messages.modalMessageSentTo)}
</p>
<p className="pl-2">
{messageContent.sent_to}
</p>
</div>
<hr className="py-2" />
<div>
<p>
{intl.formatMessage(messages.modalMessageBody)}
</p>
<div dangerouslySetInnerHTML={{ __html: messageContent.email.html_message }} />
</div>
</div>
)}
onClose={() => setIsMessageModalOpen(false)}
/>
</div>
);
/**
* Render function for the email content history table. This function is responsible for displaying data inside of
* the table when the `Show Sent Email History` button is pressed on the page.
*/
const renderTable = () => {
// Do a little data manipulation to make it easier to display what we want in the table. Pull the email subject out
// of the email data. Transforms the `sent_to` array to a string for easier display in our table.
const tableData = emailHistoryData.map((item) => ({
...item,
subject: item.email.subject,
sent_to: item.sent_to.join(', '),
}));
return (
<div className="pb-3">
<p className="font-italic">
{intl.formatMessage(messages.emailHistoryTableViewMessageInstructions)}
</p>
<DataTable
itemCount={emailHistoryData.length}
columns={[
{
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderSubject)}`,
accessor: 'subject',
},
{
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderAuthor)}`,
accessor: 'requester',
},
{
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderRecipients)}`,
accessor: 'sent_to',
},
{
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderTimeSent)}`,
accessor: 'created',
},
{
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderNumberSent)}`,
accessor: 'number_sent',
},
]}
data={tableData}
additionalColumns={[
{
id: 'view_message',
Header: `${intl.formatMessage(messages.emailHistoryTableColumnHeaderViewMessage)}`,
Cell: ({ row }) => (
<Button variant="link" className="px-1" onClick={() => onViewMessageClick(tableData[row.index])}>
{intl.formatMessage(messages.buttonViewMessage)}
</Button>
),
},
]}
/>
</div>
);
};
/**
* Today there can be three states which the renderTableData function will handle:
* 1. There was an error retrieving data from edx-platform and we can't display anything (for now).
* 2. There is no email history for this course-run and we have nothing to display to the end user.
* 3. We were able to receive historical email content and it will be presented in a table.
*/
const renderTableData = () => {
if (errorRetrievingData) {
return renderError();
}
if (!emailHistoryData.length) {
return renderEmpty();
}
return renderTable();
};
return (
<div>
<div>
{messageContent && renderMessageModal()}
</div>
<div>
<p>
<FormattedMessage
id="bulk.email.content.history.section.heading"
defaultMessage="To see the content of previously sent emails, click this button:"
description="Instructions for course staff and admins to view historical bulk course email content."
/>
{intl.formatMessage(messages.emailHistoryTableSectionButtonHeader)}
</p>
<button type="button" className="btn btn-outline-primary mb-2">
<FormattedMessage
id="bulk.email.view.email.content.history.button"
defaultMessage="Show Sent Email History"
description="Button that displays a table with historical sent email data for this course-run"
/>
</button>
<Button variant="outline-primary" className="btn btn-outline-primary mb-2" onClick={async () => { await fetchSentEmailHistoryData(); }}>
{intl.formatMessage(messages.emailHistoryTableSectionButton)}
</Button>
{showHistoricalEmailContentTable && renderTableData()}
</div>
</div>
);
}
BulkEmailContentHistory.propTypes = {
intl: intlShape.isRequired,
row: PropTypes.shape({
index: PropTypes.number,
}),
};
BulkEmailContentHistory.defaultProps = {
row: {},
};
export default injectIntl(BulkEmailContentHistory);

View File

@@ -0,0 +1,78 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
/* BulkEmailContentHistory.jsx Messages */
errorFetchingData: {
id: 'bulk.email.content.history.table.alert.errorFetchingData',
defaultMessage: 'An error occurred retrieving email history data for this course. Please try again later.',
},
noEmailData: {
id: 'bulk.email.content.history.table.alert.noEmailData',
defaultMessage: 'There is no email history for this course',
},
buttonViewMessage: {
id: 'bulk.email.content.history.table.button.viewMessage',
defaultMessage: 'View Message',
},
modalMessageSubject: {
id: 'bulk.email.content.history.table.modal.subject',
defaultMessage: 'Subject:',
},
modalMessageSentBy: {
id: 'bulk.email.content.history.table.modal.sentBy',
defaultMessage: 'Sent by:',
},
modalMessageTimeSent: {
id: 'bulk.email.content.history.table.modal.timeSent',
defaultMessage: 'Time sent:',
},
modalMessageSentTo: {
id: 'bulk.email.content.history.table.modal.sentTo',
defaultMessage: 'Sent to:',
},
modalMessageBody: {
id: 'bulk.email.content.history.table.modal.messageBody',
defaultMessage: 'Message:',
},
emailHistoryTableViewMessageInstructions: {
id: 'bulk.email.content.history.table.viewMessageInstructions',
defaultMessage: 'To read a sent email message, click the `View Message` button within the table.',
},
emailHistoryTableColumnHeaderSubject: {
id: 'bulk.email.content.history.table.column.header.subject',
defaultMessage: 'Subject',
},
emailHistoryTableColumnHeaderAuthor: {
id: 'bulk.email.content.history.table.column.header.author',
defaultMessage: 'Sent By',
},
emailHistoryTableColumnHeaderRecipients: {
id: 'bulk.email.content.history.table.column.header.recipients',
defaultMessage: 'Sent To',
},
emailHistoryTableColumnHeaderTimeSent: {
id: 'bulk.email.content.history.table.column.header.timeSent',
defaultMessage: 'Time Sent',
},
emailHistoryTableColumnHeaderNumberSent: {
id: 'bulk.email.content.history.table.column.header.numberSent',
defaultMessage: 'Subject',
},
emailHistoryTableColumnHeaderViewMessage: {
id: 'bulk.email.content.history.table.column.header.viewMessage',
defaultMessage: 'View Message',
},
emailHistoryTableSectionButtonHeader: {
id: 'bulk.email.content.history.table.button.header',
defaultMessage: 'To see the content of previously sent emails, click this button:',
},
emailHistoryTableSectionButton: {
id: 'bulk.email.content.history.table.button',
defaultMessage: 'Show Sent Email History',
},
/* BulkEmailTaskManager.jsx messages */
/* BulkEmailPendingTasks.jsx messages */
/* BulkEmailTaskHistory.jsx messages */
});
export default messages;