feat: [AXIMST-25] Course unit - Alert notification about unpublished changes (#135)

* feat: [AXIMST-25] added alert notification about unpublished changes

* feat: added tests

* feat: added translations
This commit is contained in:
Peter Kulko
2024-01-26 17:33:02 +02:00
committed by Adolfo R. Brandes
parent e4d88fb1fa
commit 9021fccdb7
4 changed files with 49 additions and 1 deletions

View File

@@ -4,11 +4,13 @@ import { useParams } from 'react-router-dom';
import { Container, Layout, Stack } from '@openedx/paragon';
import { useIntl, injectIntl } from '@edx/frontend-platform/i18n';
import { ErrorAlert } from '@edx/frontend-lib-content-components';
import { Warning as WarningIcon } from '@openedx/paragon/icons';
import { getProcessingNotification } from '../generic/processing-notification/data/selectors';
import SubHeader from '../generic/sub-header/SubHeader';
import { RequestStatus } from '../data/constants';
import getPageHeadTitle from '../generic/utils';
import AlertMessage from '../generic/alert-message';
import ProcessingNotification from '../generic/processing-notification';
import InternetConnectionAlert from '../generic/internet-connection-alert';
import Loading from '../generic/Loading';
@@ -33,6 +35,7 @@ const CourseUnit = ({ courseId }) => {
savingStatus,
isTitleEditFormOpen,
isErrorAlert,
isLastUnpublishedVersion,
isInternetConnectionAlertFailed,
unitXBlockActions,
handleTitleEditSubmit,
@@ -94,6 +97,13 @@ const CourseUnit = ({ courseId }) => {
xl={[{ span: 9 }, { span: 3 }]}
>
<Layout.Element>
{isLastUnpublishedVersion && (
<AlertMessage
title={intl.formatMessage(messages.alertUnpublishedVersion)}
variant="warning"
icon={WarningIcon}
/>
)}
<Stack gap={4} className="mb-4">
{courseVerticalChildren.children.map(({ name, blockId: id, shouldScroll }) => (
<CourseXBlock

View File

@@ -31,12 +31,13 @@ import {
courseVerticalChildrenMock,
} from './__mocks__';
import { executeThunk } from '../utils';
import CourseUnit from './CourseUnit';
import headerNavigationsMessages from './header-navigations/messages';
import headerTitleMessages from './header-title/messages';
import courseSequenceMessages from './course-sequence/messages';
import sidebarMessages from './sidebar/messages';
import { extractCourseUnitId } from './sidebar/utils';
import CourseUnit from './CourseUnit';
import messages from './messages';
import deleteModalMessages from '../generic/delete-modal/messages';
import courseXBlockMessages from './course-xblock/messages';
@@ -353,6 +354,36 @@ describe('<CourseUnit />', () => {
});
});
it('should display a warning alert for unpublished course unit version', async () => {
const { getByRole } = render(<RootWrapper />);
await waitFor(() => {
const unpublishedAlert = getByRole('alert', { class: 'course-unit-unpublished-alert' });
expect(unpublishedAlert).toHaveTextContent(messages.alertUnpublishedVersion.defaultMessage);
expect(unpublishedAlert).toHaveClass('alert-warning');
});
});
it('should not display an unpublished alert for a course unit with explicit staff lock and unpublished status', async () => {
const { queryByRole } = render(<RootWrapper />);
axiosMock
.onGet(getCourseUnitApiUrl(courseId))
.reply(200, {
...courseUnitIndexMock,
has_explicit_staff_lock: true,
release_date: null,
published: false,
});
await executeThunk(fetchCourseUnitQuery(courseId), store.dispatch);
await waitFor(() => {
const unpublishedAlert = queryByRole('alert', { class: 'course-unit-unpublished-alert' });
expect(unpublishedAlert).toBeNull();
});
});
it('checks whether xblock is deleted when corresponding delete button is clicked', async () => {
axiosMock
.onDelete(getXBlockBaseApiUrl(courseVerticalChildrenMock.children[0].block_id))

View File

@@ -36,6 +36,8 @@ export const useCourseUnit = ({ courseId, blockId }) => {
const navigate = useNavigate();
const isTitleEditFormOpen = useSelector(state => state.courseUnit.isTitleEditFormOpen);
const isQueryPending = useSelector(state => state.courseUnit.isQueryPending);
const { hasExplicitStaffLock, published, releaseDate } = courseUnit;
const isLastUnpublishedVersion = !hasExplicitStaffLock && published && releaseDate;
const unitTitle = courseUnit.metadata?.displayName || '';
const sequenceId = courseUnit.ancestorInfo?.ancestors[0].id;
@@ -108,6 +110,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
savingStatus,
isQueryPending,
isErrorAlert,
isLastUnpublishedVersion,
isLoading: loadingStatus.fetchUnitLoadingStatus === RequestStatus.IN_PROGRESS
|| loadingStatus.courseSectionVerticalLoadingStatus === RequestStatus.IN_PROGRESS,
isTitleEditFormOpen,

View File

@@ -5,6 +5,10 @@ const messages = defineMessages({
id: 'course-authoring.course-unit.general.alert.error.description',
defaultMessage: 'Unable to {actionName} {type}. Please try again.',
},
alertUnpublishedVersion: {
id: 'course-authoring.course-unit.general.alert.unpublished-version.description',
defaultMessage: 'Note: The last published version of this unit is live. By publishing changes you will change the student experience.',
},
});
export default messages;