Skip to content

Commit

Permalink
feat: [FC-0044] Unit page - Manage access modal (unit & xblocks)
Browse files Browse the repository at this point in the history
  • Loading branch information
ihor-romaniuk committed Apr 3, 2024
1 parent 5247ec5 commit 8e145d3
Show file tree
Hide file tree
Showing 37 changed files with 1,185 additions and 329 deletions.
7 changes: 7 additions & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ export const DECODED_ROUTES = {
'/container/:blockId',
],
};

export const COURSE_BLOCK_NAMES = ({
chapter: { id: 'chapter', name: 'Section' },
sequential: { id: 'sequential', name: 'Subsection' },
vertical: { id: 'vertical', name: 'Unit' },
component: { id: 'component', name: 'Component' },
});
12 changes: 8 additions & 4 deletions src/course-outline/CourseOutline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ import SubHeader from '../generic/sub-header/SubHeader';
import ProcessingNotification from '../generic/processing-notification';
import InternetConnectionAlert from '../generic/internet-connection-alert';
import DeleteModal from '../generic/delete-modal/DeleteModal';
import ConfigureModal from '../generic/configure-modal/ConfigureModal';
import AlertMessage from '../generic/alert-message';
import getPageHeadTitle from '../generic/utils';
import { getCurrentItem } from './data/selectors';
import { getCurrentItem, getProctoredExamsFlag } from './data/selectors';
import { COURSE_BLOCK_NAMES } from './constants';
import HeaderNavigations from './header-navigations/HeaderNavigations';
import OutlineSideBar from './outline-sidebar/OutlineSidebar';
Expand All @@ -43,7 +44,6 @@ import UnitCard from './unit-card/UnitCard';
import HighlightsModal from './highlights-modal/HighlightsModal';
import EmptyPlaceholder from './empty-placeholder/EmptyPlaceholder';
import PublishModal from './publish-modal/PublishModal';
import ConfigureModal from './configure-modal/ConfigureModal';
import PageAlerts from './page-alerts/PageAlerts';
import DraggableList from './drag-helper/DraggableList';
import {
Expand Down Expand Up @@ -129,8 +129,10 @@ const CourseOutline = ({ courseId }) => {
title: processingNotificationTitle,
} = useSelector(getProcessingNotification);

const { category } = useSelector(getCurrentItem);
const deleteCategory = COURSE_BLOCK_NAMES[category]?.name.toLowerCase();
const currentItemData = useSelector(getCurrentItem);
const deleteCategory = COURSE_BLOCK_NAMES[currentItemData.category]?.name.toLowerCase();

const enableProctoredExams = useSelector(getProctoredExamsFlag);

/**
* Move section to new index
Expand Down Expand Up @@ -431,6 +433,8 @@ const CourseOutline = ({ courseId }) => {
isOpen={isConfigureModalOpen}
onClose={handleConfigureModalClose}
onConfigureSubmit={handleConfigureItemSubmit}
currentItemData={currentItemData}
enableProctoredExams={enableProctoredExams}
/>
<DeleteModal
category={deleteCategory}
Expand Down
1 change: 0 additions & 1 deletion src/course-outline/CourseOutline.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
@import "./empty-placeholder/EmptyPlaceholder";
@import "./highlights-modal/HighlightsModal";
@import "./publish-modal/PublishModal";
@import "./configure-modal/ConfigureModal";
@import "./drag-helper/SortableItem";
@import "./xblock-status/XBlockStatus";
@import "./paste-button/PasteButton";
5 changes: 3 additions & 2 deletions src/course-outline/CourseOutline.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ import {
import { executeThunk } from '../utils';
import { COURSE_BLOCK_NAMES, VIDEO_SHARING_OPTIONS } from './constants';
import CourseOutline from './CourseOutline';
import messages from './messages';

import configureModalMessages from '../generic/configure-modal/messages';
import headerMessages from './header-navigations/messages';
import cardHeaderMessages from './card-header/messages';
import enableHighlightsModalMessages from './enable-highlights-modal/messages';
import statusBarMessages from './status-bar/messages';
import configureModalMessages from './configure-modal/messages';
import pasteButtonMessages from './paste-button/messages';
import subsectionMessages from './subsection-card/messages';
import pageAlertMessages from './page-alerts/messages';
Expand All @@ -55,6 +55,7 @@ import {
moveSubsection,
moveUnit,
} from './drag-helper/utils';
import messages from './messages';

let axiosMock;
let store;
Expand Down
8 changes: 7 additions & 1 deletion src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const CourseUnit = ({ courseId }) => {
handleTitleEdit,
handleInternetConnectionFailed,
handleCreateNewCourseXBlock,
handleConfigureSubmit,
courseVerticalChildren,
} = useCourseUnit({ courseId, blockId });

Expand Down Expand Up @@ -85,6 +86,7 @@ const CourseUnit = ({ courseId }) => {
isTitleEditFormOpen={isTitleEditFormOpen}
handleTitleEdit={handleTitleEdit}
handleTitleEditSubmit={handleTitleEditSubmit}
handleConfigureSubmit={handleConfigureSubmit}
/>
)}
breadcrumbs={(
Expand Down Expand Up @@ -119,16 +121,20 @@ const CourseUnit = ({ courseId }) => {
)}
<Stack gap={4} className="mb-4">
{courseVerticalChildren.children.map(({
name, blockId: id, blockType: type, shouldScroll,
name, blockId: id, blockType: type, shouldScroll, userPartitionInfo, validationMessages,
}) => (
<CourseXBlock
id={id}
key={id}
title={name}
type={type}
blockId={blockId}
validationMessages={validationMessages}
shouldScroll={shouldScroll}
unitXBlockActions={unitXBlockActions}
handleConfigureSubmit={handleConfigureSubmit}
data-testid="course-xblock"
userPartitionInfo={userPartitionInfo}
/>
))}
</Stack>
Expand Down
1 change: 1 addition & 0 deletions src/course-unit/CourseUnit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
@import "./add-component/AddComponent";
@import "./course-xblock/CourseXBlock";
@import "./sidebar/Sidebar";
@import "./header-title/HeaderTitle";
79 changes: 75 additions & 4 deletions src/course-unit/CourseUnit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ 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 configureModalMessages from '../generic/configure-modal/messages';
import courseXBlockMessages from './course-xblock/messages';
import addComponentMessages from './add-component/messages';
import { PUBLISH_TYPES, UNIT_VISIBILITY_STATES } from './constants';
import { getContentTaxonomyTagsApiUrl, getContentTaxonomyTagsCountApiUrl } from '../content-tags-drawer/data/api';
import messages from './messages';

let axiosMock;
let store;
Expand Down Expand Up @@ -571,6 +572,7 @@ describe('<CourseUnit />', () => {
name: 'New Cloned XBlock',
block_id: '1234567890',
block_type: 'drag-and-drop-v2',
user_partition_info: {},
},
],
});
Expand All @@ -594,7 +596,7 @@ describe('<CourseUnit />', () => {
});
});

it('should toggle visibility and update course unit state accordingly', async () => {
it('should toggle visibility from sidebar and update course unit state accordingly', async () => {
const { getByRole, getByTestId } = render(<RootWrapper />);
let courseUnitSidebar;
let draftUnpublishedChangesHeading;
Expand All @@ -617,7 +619,7 @@ describe('<CourseUnit />', () => {
axiosMock
.onPost(getXBlockBaseApiUrl(blockId), {
publish: PUBLISH_TYPES.republish,
metadata: { visible_to_staff_only: true },
metadata: { visible_to_staff_only: true, group_access: null },
})
.reply(200, { dummy: 'value' });
axiosMock
Expand Down Expand Up @@ -654,7 +656,7 @@ describe('<CourseUnit />', () => {
axiosMock
.onPost(getXBlockBaseApiUrl(blockId), {
publish: PUBLISH_TYPES.republish,
metadata: { visible_to_staff_only: null },
metadata: { visible_to_staff_only: null, group_access: null },
})
.reply(200, { dummy: 'value' });
axiosMock
Expand Down Expand Up @@ -942,4 +944,73 @@ describe('<CourseUnit />', () => {
.replace('{sectionName}', courseUnitIndexMock.release_date_from),
)).toBeInTheDocument();
});

it('should toggle visibility from header configure modal and update course unit state accordingly', async () => {
const { getByRole, getByTestId } = render(<RootWrapper />);
let courseUnitSidebar;
let sidebarVisibilityCheckbox;
let modalVisibilityCheckbox;
let configureModal;
let restrictAccessSelect;

await waitFor(() => {
courseUnitSidebar = getByTestId('course-unit-sidebar');
sidebarVisibilityCheckbox = within(courseUnitSidebar)
.getByLabelText(sidebarMessages.visibilityCheckboxTitle.defaultMessage);
expect(sidebarVisibilityCheckbox).not.toBeChecked();

const headerConfigureBtn = getByRole('button', { name: /settings/i });
expect(headerConfigureBtn).toBeInTheDocument();

userEvent.click(headerConfigureBtn);
configureModal = getByTestId('configure-modal');
restrictAccessSelect = within(configureModal)
.getByRole('combobox', { name: configureModalMessages.restrictAccessTo.defaultMessage });
expect(within(configureModal)
.getByText(configureModalMessages.unitVisibility.defaultMessage)).toBeInTheDocument();
expect(within(configureModal)
.getByText(configureModalMessages.restrictAccessTo.defaultMessage)).toBeInTheDocument();
expect(restrictAccessSelect).toBeInTheDocument();
expect(restrictAccessSelect).toHaveValue('-1');

modalVisibilityCheckbox = within(configureModal)
.getByRole('checkbox', { name: configureModalMessages.hideFromLearners.defaultMessage });
expect(modalVisibilityCheckbox).not.toBeChecked();

userEvent.click(modalVisibilityCheckbox);
expect(modalVisibilityCheckbox).toBeChecked();

userEvent.selectOptions(restrictAccessSelect, '0');
const [, group1Checkbox] = within(configureModal).getAllByRole('checkbox');

userEvent.click(group1Checkbox);
expect(group1Checkbox).toBeChecked();
});

axiosMock
.onPost(getXBlockBaseApiUrl(courseUnitIndexMock.id), {
publish: null,
metadata: { visible_to_staff_only: true, group_access: { 50: [2] } },
})
.reply(200, { dummy: 'value' });
axiosMock
.onGet(getCourseUnitApiUrl(blockId))
.replyOnce(200, {
...courseUnitIndexMock,
visibility_state: UNIT_VISIBILITY_STATES.staffOnly,
has_explicit_staff_lock: true,
});

const modalSaveBtn = within(configureModal)
.getByRole('button', { name: configureModalMessages.saveButton.defaultMessage });
userEvent.click(modalSaveBtn);

await waitFor(() => {
expect(sidebarVisibilityCheckbox).toBeChecked();
expect(within(courseUnitSidebar)
.getByText(sidebarMessages.sidebarTitleVisibleToStaffOnly.defaultMessage)).toBeInTheDocument();
expect(within(courseUnitSidebar)
.getByText(sidebarMessages.visibilityStaffOnlyTitle.defaultMessage)).toBeInTheDocument();
});
});
});
Loading

0 comments on commit 8e145d3

Please sign in to comment.