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:
committed by
Adolfo R. Brandes
parent
e4d88fb1fa
commit
9021fccdb7
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user