Skip to content

Commit

Permalink
fix: hide due dates config and add discussion enable setting (#1267)
Browse files Browse the repository at this point in the history
Hide release and due dates config in self paced courses and
discussion enable setting for unit in outline.

Co-authored-by: Dima Alipov <[email protected]>
  • Loading branch information
DmytroAlipov and Dima Alipov authored Sep 10, 2024
1 parent 4556562 commit 8abcbe0
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 115 deletions.
1 change: 1 addition & 0 deletions src/course-outline/CourseOutline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ const CourseOutline = ({ courseId }) => {
onConfigureSubmit={handleConfigureItemSubmit}
currentItemData={currentItemData}
enableProctoredExams={enableProctoredExams}
isSelfPaced={statusBarData.isSelfPaced}
/>
<DeleteModal
category={deleteCategory}
Expand Down
11 changes: 11 additions & 0 deletions src/course-outline/CourseOutline.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,7 @@ describe('<CourseOutline />', () => {
publish: 'republish',
metadata: {
visible_to_staff_only: isVisibleToStaffOnly,
discussion_enabled: false,
group_access: newGroupAccess,
},
})
Expand All @@ -1427,6 +1428,7 @@ describe('<CourseOutline />', () => {

// after configuraiton response
unit.visibilityState = 'staff_only';
unit.discussion_enabled = false;
unit.userPartitionInfo = {
selectablePartitions: [
{
Expand Down Expand Up @@ -1469,6 +1471,11 @@ describe('<CourseOutline />', () => {
)).toBeInTheDocument();
let visibilityCheckbox = await within(configureModal).findByTestId('unit-visibility-checkbox');
await act(async () => fireEvent.click(visibilityCheckbox));
let discussionCheckbox = await within(configureModal).findByLabelText(
configureModalMessages.discussionEnabledCheckbox.defaultMessage,
);
expect(discussionCheckbox).toBeChecked();
await act(async () => fireEvent.click(discussionCheckbox));

let groupeType = await within(configureModal).findByTestId('group-type-select');
fireEvent.change(groupeType, { target: { value: '0' } });
Expand All @@ -1485,6 +1492,10 @@ describe('<CourseOutline />', () => {
configureModal = await findByTestId('configure-modal');
visibilityCheckbox = await within(configureModal).findByTestId('unit-visibility-checkbox');
expect(visibilityCheckbox).toBeChecked();
discussionCheckbox = await within(configureModal).findByLabelText(
configureModalMessages.discussionEnabledCheckbox.defaultMessage,
);
expect(discussionCheckbox).not.toBeChecked();

groupeType = await within(configureModal).findByTestId('group-type-select');
expect(groupeType).toHaveValue('0');
Expand Down
3 changes: 2 additions & 1 deletion src/course-outline/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -311,14 +311,15 @@ export async function configureCourseSubsection(
* @param {object} groupAccess
* @returns {Promise<Object>}
*/
export async function configureCourseUnit(unitId, isVisibleToStaffOnly, groupAccess) {
export async function configureCourseUnit(unitId, isVisibleToStaffOnly, groupAccess, discussionEnabled) {
const { data } = await getAuthenticatedHttpClient()
.post(getCourseItemApiUrl(unitId), {
publish: 'republish',
metadata: {
// The backend expects metadata.visible_to_staff_only to either true or null
visible_to_staff_only: isVisibleToStaffOnly ? true : null,
group_access: groupAccess,
discussion_enabled: discussionEnabled,
},
});

Expand Down
4 changes: 2 additions & 2 deletions src/course-outline/data/thunk.js
Original file line number Diff line number Diff line change
Expand Up @@ -334,11 +334,11 @@ export function configureCourseSubsectionQuery(
};
}

export function configureCourseUnitQuery(itemId, sectionId, isVisibleToStaffOnly, groupAccess) {
export function configureCourseUnitQuery(itemId, sectionId, isVisibleToStaffOnly, groupAccess, discussionEnabled) {
return async (dispatch) => {
dispatch(configureCourseItemQuery(
sectionId,
async () => configureCourseUnit(itemId, isVisibleToStaffOnly, groupAccess),
async () => configureCourseUnit(itemId, isVisibleToStaffOnly, groupAccess, discussionEnabled),
));
};
}
Expand Down
1 change: 1 addition & 0 deletions src/course-outline/highlights-modal/HighlightsModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const HighlightsModal = ({
onClose={onClose}
hasCloseButton
isFullscreenOnMobile
isOverflowVisible={false}
>
<ModalDialog.Header className="highlights-modal__header">
<ModalDialog.Title>
Expand Down
1 change: 1 addition & 0 deletions src/course-outline/publish-modal/PublishModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const PublishModal = ({
onClose={onClose}
hasCloseButton
isFullscreenOnMobile
isOverflowVisible={false}
>
<ModalDialog.Header className="publish-modal__header">
<ModalDialog.Title>
Expand Down
86 changes: 47 additions & 39 deletions src/generic/configure-modal/BasicTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const BasicTab = ({
setFieldValue,
courseGraders,
isSubsection,
isSelfPaced,
}) => {
const intl = useIntl();

Expand All @@ -27,26 +28,30 @@ const BasicTab = ({

return (
<>
<h5 className="mt-4 text-gray-700"><FormattedMessage {...messages.releaseDateAndTime} /></h5>
<hr />
<div data-testid="release-date-stack">
<Stack className="mt-3" direction="horizontal" gap={5}>
<DatepickerControl
type={DATEPICKER_TYPES.date}
value={releaseDate}
label={intl.formatMessage(messages.releaseDate)}
controlName="state-date"
onChange={(val) => setFieldValue('releaseDate', val)}
/>
<DatepickerControl
type={DATEPICKER_TYPES.time}
value={releaseDate}
label={intl.formatMessage(messages.releaseTimeUTC)}
controlName="start-time"
onChange={(val) => setFieldValue('releaseDate', val)}
/>
</Stack>
</div>
{!isSelfPaced && (
<>
<h5 className="mt-4 text-gray-700"><FormattedMessage {...messages.releaseDateAndTime} /></h5>
<hr />
<div data-testid="release-date-stack">
<Stack className="mt-3" direction="horizontal" gap={5}>
<DatepickerControl
type={DATEPICKER_TYPES.date}
value={releaseDate}
label={intl.formatMessage(messages.releaseDate)}
controlName="state-date"
onChange={(val) => setFieldValue('releaseDate', val)}
/>
<DatepickerControl
type={DATEPICKER_TYPES.time}
value={releaseDate}
label={intl.formatMessage(messages.releaseTimeUTC)}
controlName="start-time"
onChange={(val) => setFieldValue('releaseDate', val)}
/>
</Stack>
</div>
</>
)}
{
isSubsection && (
<div>
Expand All @@ -66,25 +71,27 @@ const BasicTab = ({
{createOptions()}
</Form.Control>
</Form.Group>
<div data-testid="due-date-stack">
<Stack className="mt-3" direction="horizontal" gap={5}>
<DatepickerControl
type={DATEPICKER_TYPES.date}
value={dueDate}
label={intl.formatMessage(messages.dueDate)}
controlName="state-date"
onChange={(val) => setFieldValue('dueDate', val)}
data-testid="due-date-picker"
/>
<DatepickerControl
type={DATEPICKER_TYPES.time}
value={dueDate}
label={intl.formatMessage(messages.dueTimeUTC)}
controlName="start-time"
onChange={(val) => setFieldValue('dueDate', val)}
/>
</Stack>
</div>
{!isSelfPaced && (
<div data-testid="due-date-stack">
<Stack className="mt-3" direction="horizontal" gap={5}>
<DatepickerControl
type={DATEPICKER_TYPES.date}
value={dueDate}
label={intl.formatMessage(messages.dueDate)}
controlName="state-date"
onChange={(val) => setFieldValue('dueDate', val)}
data-testid="due-date-picker"
/>
<DatepickerControl
type={DATEPICKER_TYPES.time}
value={dueDate}
label={intl.formatMessage(messages.dueTimeUTC)}
controlName="start-time"
onChange={(val) => setFieldValue('dueDate', val)}
/>
</Stack>
</div>
)}
</div>
)
}
Expand All @@ -101,6 +108,7 @@ BasicTab.propTypes = {
}).isRequired,
courseGraders: PropTypes.arrayOf(PropTypes.string).isRequired,
setFieldValue: PropTypes.func.isRequired,
isSelfPaced: PropTypes.bool.isRequired,
};

export default injectIntl(BasicTab);
11 changes: 10 additions & 1 deletion src/generic/configure-modal/ConfigureModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const ConfigureModal = ({
currentItemData,
enableProctoredExams,
isXBlockComponent,
isSelfPaced,
}) => {
const intl = useIntl();
const {
Expand Down Expand Up @@ -58,6 +59,7 @@ const ConfigureModal = ({
supportsOnboarding,
showReviewRules,
onlineProctoringRules,
discussionEnabled,
} = currentItemData;

const getSelectedGroups = () => {
Expand Down Expand Up @@ -98,6 +100,7 @@ const ConfigureModal = ({
// by default it is -1 i.e. accessible to all learners & staff
selectedPartitionIndex: userPartitionInfo?.selectedPartitionIndex,
selectedGroups: getSelectedGroups(),
discussionEnabled,
};

const validationSchema = Yup.object().shape({
Expand Down Expand Up @@ -127,6 +130,7 @@ const ConfigureModal = ({
).nullable(true),
selectedPartitionIndex: Yup.number().integer(),
selectedGroups: Yup.array().of(Yup.string()),
discussionEnabled: Yup.boolean(),
});

const isSubsection = category === COURSE_BLOCK_NAMES.sequential.id;
Expand Down Expand Up @@ -168,7 +172,7 @@ const ConfigureModal = ({
const partitionId = userPartitionInfo.selectablePartitions[data.selectedPartitionIndex].id;
groupAccess[partitionId] = data.selectedGroups.map(g => parseInt(g, 10));
}
onConfigureSubmit(data.isVisibleToStaffOnly, groupAccess);
onConfigureSubmit(data.isVisibleToStaffOnly, groupAccess, data.discussionEnabled);
break;
default:
break;
Expand All @@ -186,6 +190,7 @@ const ConfigureModal = ({
setFieldValue={setFieldValue}
isSubsection={isSubsection}
courseGraders={courseGraders === 'undefined' ? [] : courseGraders}
isSelfPaced={isSelfPaced}
/>
</Tab>
<Tab eventKey="visibility" title={intl.formatMessage(messages.visibilityTabTitle)}>
Expand All @@ -208,6 +213,7 @@ const ConfigureModal = ({
setFieldValue={setFieldValue}
isSubsection={isSubsection}
courseGraders={courseGraders === 'undefined' ? [] : courseGraders}
isSelfPaced={isSelfPaced}
/>
</Tab>
<Tab eventKey="visibility" title={intl.formatMessage(messages.visibilityTabTitle)}>
Expand Down Expand Up @@ -259,6 +265,7 @@ const ConfigureModal = ({
onClose={onClose}
hasCloseButton
isFullscreenOnMobile
isOverflowVisible={false}
>
<div data-testid="configure-modal">
<ModalDialog.Header className="configure-modal__header">
Expand Down Expand Up @@ -358,8 +365,10 @@ ConfigureModal.propTypes = {
supportsOnboarding: PropTypes.bool,
showReviewRules: PropTypes.bool,
onlineProctoringRules: PropTypes.string,
discussionEnabled: PropTypes.bool.isRequired,
}).isRequired,
isXBlockComponent: PropTypes.bool,
isSelfPaced: PropTypes.bool.isRequired,
};

export default ConfigureModal;
14 changes: 13 additions & 1 deletion src/generic/configure-modal/ConfigureModal.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const renderComponent = () => render(
onClose={onCloseMock}
onConfigureSubmit={onConfigureSubmitMock}
currentItemData={currentSectionMock}
isSelfPaced={false}
/>
</IntlProvider>,
</AppProvider>,
Expand Down Expand Up @@ -85,14 +86,16 @@ describe('<ConfigureModal /> for Section', () => {
});
});

const renderSubsectionComponent = () => render(
const renderSubsectionComponent = (props) => render(
<AppProvider store={store}>
<IntlProvider locale="en">
<ConfigureModal
isOpen
onClose={onCloseMock}
onConfigureSubmit={onConfigureSubmitMock}
currentItemData={currentSubsectionMock}
isSelfPaced={false}
{...props}
/>
</IntlProvider>,
</AppProvider>,
Expand Down Expand Up @@ -129,6 +132,14 @@ describe('<ConfigureModal /> for Subsection', () => {
expect(getByRole('button', { name: messages.saveButton.defaultMessage })).toBeInTheDocument();
});

it('hides release and due dates for self paced courses', () => {
const { queryByText } = renderSubsectionComponent({ isSelfPaced: true });
expect(queryByText(messages.releaseDate.defaultMessage)).not.toBeInTheDocument();
expect(queryByText(messages.releaseTimeUTC.defaultMessage)).not.toBeInTheDocument();
expect(queryByText(messages.dueDate.defaultMessage)).not.toBeInTheDocument();
expect(queryByText(messages.dueTimeUTC.defaultMessage)).not.toBeInTheDocument();
});

it('switches to the subsection Visibility tab and renders correctly', () => {
const { getByRole, getByText } = renderSubsectionComponent();

Expand Down Expand Up @@ -198,6 +209,7 @@ describe('<ConfigureModal /> for Unit', () => {
expect(getByText(`${currentUnitMock.displayName} settings`)).toBeInTheDocument();
expect(getByText(messages.unitVisibility.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.hideFromLearners.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.discussionEnabledCheckbox.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.restrictAccessTo.defaultMessage)).toBeInTheDocument();
expect(getByText(messages.unitSelectGroupType.defaultMessage)).toBeInTheDocument();

Expand Down
Loading

0 comments on commit 8abcbe0

Please sign in to comment.