diff --git a/plugins/communications-app/ScheduleSection/index.jsx b/plugins/communications-app/ScheduleSection/index.jsx
index 588b25ae..f398a6d8 100644
--- a/plugins/communications-app/ScheduleSection/index.jsx
+++ b/plugins/communications-app/ScheduleSection/index.jsx
@@ -7,6 +7,7 @@ import {
Form,
Icon,
Toast,
+ Spinner,
} from '@edx/paragon';
import {
SpinnerSimple,
@@ -23,8 +24,9 @@ import { useSelector, useDispatch } from '@communications-app/src/components/bul
import { actionCreators as formActions } from '@communications-app/src/components/bulk-email-tool/bulk-email-form/BuildEmailFormExtensible/context/reducer';
import messages from './messages';
+import './styles.scss';
-const formStatusToast = ['error', 'complete', 'completeSchedule'];
+const formStatusToast = ['error', 'complete', 'completeSchedule', 'loadingTeams'];
const ScheduleSection = ({ openTaskAlert }) => {
const intl = useIntl();
@@ -39,6 +41,7 @@ const ScheduleSection = ({ openTaskAlert }) => {
isEditMode,
formStatus,
isScheduledSubmitted = false,
+ isLoadingTeams = false,
} = formData;
const formStatusErrors = {
@@ -89,7 +92,7 @@ const ScheduleSection = ({ openTaskAlert }) => {
complete: ,
completeSchedule: ,
error: ,
- loadingTeams: ,
+ isLoadingTeams: ,
}), []);
const statefulButtonLabels = useMemo(() => ({
@@ -100,15 +103,15 @@ const ScheduleSection = ({ openTaskAlert }) => {
complete: intl.formatMessage(messages.ScheduleSectionSubmitButtonComplete),
completeSchedule: intl.formatMessage(messages.ScheduleSectionSubmitButtonCompleteSchedule),
error: intl.formatMessage(messages.ScheduleSectionSubmitButtonError),
- loadingTeams: intl.formatMessage(messages.ScheduleSectionSubmitButtonLoadingTeams),
+ loadingTeams: intl.formatMessage(messages.ScheduleSectionSubmitButtonDefault),
}), [intl]);
const statefulButtonDisableStates = useMemo(() => [
'pending',
'complete',
'completeSchedule',
- 'loadingTeams',
- ], []);
+ isLoadingTeams ? 'loadingTeams' : '',
+ ], [isLoadingTeams]);
return (
@@ -150,16 +153,32 @@ const ScheduleSection = ({ openTaskAlert }) => {
)}
-
+
+
+ {isLoadingTeams && (
+
+ )}
+ >
+ {intl.formatMessage(messages.ScheduleSectionSubmitButtonFeedBackLoadingTeams)}
+
+ )}
+
(
+
+ )}
+ >
+ {title}
+
+);
+
+FeedbackMessage.propTypes = {
+ title: PropTypes.string.isRequired,
+};
+
+export default FeedbackMessage;
diff --git a/plugins/communications-app/TeamEmails/FeedbackMessage.scss b/plugins/communications-app/TeamEmails/FeedbackMessage.scss
new file mode 100644
index 00000000..2ede6c9b
--- /dev/null
+++ b/plugins/communications-app/TeamEmails/FeedbackMessage.scss
@@ -0,0 +1,8 @@
+$medium-spinner: 15px;
+
+.loading-teams-spinner {
+ &__medium {
+ height: $medium-spinner;
+ width: $medium-spinner;
+ }
+}
diff --git a/plugins/communications-app/TeamEmails/FeedbackMessage.test.jsx b/plugins/communications-app/TeamEmails/FeedbackMessage.test.jsx
new file mode 100644
index 00000000..a3fae6bd
--- /dev/null
+++ b/plugins/communications-app/TeamEmails/FeedbackMessage.test.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import { render, screen } from '@testing-library/react';
+import FeedbackMessage from './FeedbackMessage';
+
+describe('FeedbackMessage Component', () => {
+ test('renders with the provided title', () => {
+ const title = 'Loading...';
+ render();
+ const feedbackMessageContainer = screen.getByTestId('feedback-message-container');
+ expect(feedbackMessageContainer).toBeInTheDocument();
+ expect(feedbackMessageContainer).toHaveTextContent(title);
+ });
+
+ test('renders the spinner element', () => {
+ render();
+ const spinnerElement = screen.getByTestId('feedback-message-spinner');
+ expect(spinnerElement).toBeInTheDocument();
+ });
+
+ test('renders the spinner with the correct CSS classes', () => {
+ render();
+ const spinnerElement = screen.getByTestId('feedback-message-spinner');
+ expect(spinnerElement).toHaveClass('mie-3 loading-teams-spinner__medium');
+ });
+});
diff --git a/plugins/communications-app/TeamEmails/index.jsx b/plugins/communications-app/TeamEmails/index.jsx
index 53abbfbc..89b4c305 100644
--- a/plugins/communications-app/TeamEmails/index.jsx
+++ b/plugins/communications-app/TeamEmails/index.jsx
@@ -8,6 +8,7 @@ import {
import { actionCreators as formActions } from '@communications-app/src/components/bulk-email-tool/bulk-email-form/BuildEmailFormExtensible/context/reducer';
import ListTeams from './ListTeams';
+import FeedbackMessage from './FeedbackMessage';
import messages from './messages';
import { getTopicsList } from './api';
import { getTeamsFromTopics, convertSnakeCaseToCamelCase } from './utils';
@@ -41,7 +42,7 @@ const TeamEmails = ({ courseId }) => {
if (next) {
fetchTeams(page + 1);
} else {
- dispatch(formActions.updateForm({ formStatus: 'default' }));
+ dispatch(formActions.updateForm({ isLoadingTeams: false }));
}
} catch (error) {
console.error('There was an error while getting teams:', error.message);
@@ -57,10 +58,10 @@ const TeamEmails = ({ courseId }) => {
useEffect(() => {
if (loadingTeams) {
- dispatch(formActions.updateForm({ formStatus: 'loadingTeams' }));
+ dispatch(formActions.updateForm({ isLoadingTeams: true }));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [formStatus, loadingTeams]);
+ }, [loadingTeams]);
useEffect(() => {
if (teams.length) {
@@ -111,6 +112,9 @@ const TeamEmails = ({ courseId }) => {
teamsSelected={checkedTeams}
onChangeCheckBox={handleChangeTeamCheckBox}
/>
+ {loadingTeams && (
+
+ )}
);
};
diff --git a/plugins/communications-app/TeamEmails/messages.js b/plugins/communications-app/TeamEmails/messages.js
index 661a8722..b957dc1c 100644
--- a/plugins/communications-app/TeamEmails/messages.js
+++ b/plugins/communications-app/TeamEmails/messages.js
@@ -7,6 +7,11 @@ const messages = defineMessages({
defaultMessage: 'Teams',
description: 'Title for checkboxes of team members',
},
+ teamEmailsFeedBackLoadingTeams: {
+ id: 'team.emails.feedback.loading.teams',
+ defaultMessage: 'Loading teams',
+ description: 'A loading shown to the user while teams are being fetching',
+ },
});
export default messages;