Skip to content

Commit

Permalink
refactor: code refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang committed May 3, 2024
1 parent ba7748e commit 0583d90
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 13 deletions.
5 changes: 5 additions & 0 deletions src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const CourseUnit = ({ courseId }) => {
movedXBlockParams,
handleRollbackMovedXBlock,
handleCloseXBlockMovedAlert,
handleNavigateToTargetUnit,
} = useCourseUnit({ courseId, blockId });

const initialXBlocksData = useMemo(() => courseVerticalChildren.children ?? [], [courseVerticalChildren.children]);
Expand Down Expand Up @@ -119,6 +120,7 @@ const CourseUnit = ({ courseId }) => {
{movedXBlockParams.isSuccess ? (
<AlertMessage
key="xblock-moved-alert"
data-testid="xblock-moved-alert"
show={movedXBlockParams.isSuccess}
variant="success"
icon={CheckCircleIcon}
Expand All @@ -134,6 +136,9 @@ const CourseUnit = ({ courseId }) => {
<Button onClick={handleRollbackMovedXBlock}>
{intl.formatMessage(messages.undoMoveButton)}
</Button>,
<Button onClick={handleNavigateToTargetUnit}>
{intl.formatMessage(messages.newLocationButton)}
</Button>,
]}
onClose={handleCloseXBlockMovedAlert}
/>
Expand Down
170 changes: 164 additions & 6 deletions src/course-unit/CourseUnit.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import userEvent from '@testing-library/user-event';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { AppProvider } from '@edx/frontend-platform/react';
import { camelCaseObject, initializeMockApp } from '@edx/frontend-platform';
import { camelCaseObject, getConfig, initializeMockApp } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { cloneDeep, set } from 'lodash';

Expand All @@ -23,20 +23,18 @@ import {
fetchCourseSectionVerticalData,
fetchCourseUnitQuery,
fetchCourseVerticalChildrenData,
rollbackUnitItemQuery,
} from './data/thunk';
import initializeStore from '../store';
import {
clipboardMockResponse,
courseCreateXblockMock,
courseSectionVerticalMock,
courseUnitIndexMock,
courseUnitMock,
courseVerticalChildrenMock,
clipboardMockResponse,
} from './__mocks__';
import {
clipboardUnit,
clipboardXBlock,
} from '../__mocks__';
import { clipboardUnit, clipboardXBlock } from '../__mocks__';
import { executeThunk } from '../utils';
import deleteModalMessages from '../generic/delete-modal/messages';
import pasteComponentMessages from '../generic/clipboard/paste-component/messages';
Expand Down Expand Up @@ -111,6 +109,17 @@ jest.mock('../generic/hooks', () => ({

global.BroadcastChannel = jest.fn(() => clipboardBroadcastChannelMock);

const getIFramePostMessages = (method) => ({
data: {
method,
params: {
targetParentLocator: courseId,
sourceDisplayName: courseVerticalChildrenMock.children[0].name,
sourceLocator: courseVerticalChildrenMock.children[0].block_id,
},
},
});

const RootWrapper = () => (
<AppProvider store={store}>
<IntlProvider locale="en">
Expand Down Expand Up @@ -1590,4 +1599,153 @@ describe('<CourseUnit />', () => {
});
});
});

describe('Edit and move modals', () => {
it('should close the edit modal when the close button is clicked', async () => {
const { getByTitle, getAllByTestId } = render(<RootWrapper />);

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, courseVerticalChildrenMock);

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

const [discussionXBlock] = getAllByTestId('course-xblock');
const xblockEditBtn = within(discussionXBlock)
.getByLabelText(courseXBlockMessages.blockAltButtonEdit.defaultMessage);

userEvent.click(xblockEditBtn);

const iframePostMsg = getIFramePostMessages('close_edit_modal');
const editModalIFrame = getByTitle('xblock-edit-modal-iframe');

expect(editModalIFrame).toHaveAttribute('src', `${getConfig().STUDIO_BASE_URL}/xblock/${courseVerticalChildrenMock.children[0].block_id}/actions/edit`);

await act(async () => window.dispatchEvent(new MessageEvent('message', iframePostMsg)));

expect(editModalIFrame).not.toBeInTheDocument();
});

it('should display success alert and close move modal when move event is triggered', async () => {
const {
getByTitle,
getByRole,
getAllByLabelText,
getByText,
} = render(<RootWrapper />);

const iframePostMsg = getIFramePostMessages('move_xblock');

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, courseVerticalChildrenMock);

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);

const xblockMoveBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonMove.defaultMessage });
userEvent.click(xblockMoveBtn);

const moveModalIFrame = getByTitle('xblock-move-modal-iframe');

await act(async () => window.dispatchEvent(new MessageEvent('message', iframePostMsg)));

expect(moveModalIFrame).not.toBeInTheDocument();
expect(getByText(messages.alertMoveSuccessTitle.defaultMessage)).toBeInTheDocument();
expect(getByText(
messages.alertMoveSuccessDescription.defaultMessage
.replace('{title}', courseVerticalChildrenMock.children[0].name),
)).toBeInTheDocument();

await waitFor(() => {
userEvent.click(getByText(/Cancel/i));
expect(moveModalIFrame).not.toBeInTheDocument();
});
});

it('should navigate to new location when new location button is clicked after successful move', async () => {
const {
getByTitle,
getByRole,
getAllByLabelText,
getByText,
} = render(<RootWrapper />);

const iframePostMsg = getIFramePostMessages('move_xblock');

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, courseVerticalChildrenMock);

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);

const xblockMoveBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonMove.defaultMessage });
userEvent.click(xblockMoveBtn);

const moveModalIFrame = getByTitle('xblock-move-modal-iframe');

await act(async () => window.dispatchEvent(new MessageEvent('message', iframePostMsg)));

expect(moveModalIFrame).not.toBeInTheDocument();
expect(getByText(messages.alertMoveSuccessTitle.defaultMessage)).toBeInTheDocument();
expect(getByText(
messages.alertMoveSuccessDescription.defaultMessage
.replace('{title}', courseVerticalChildrenMock.children[0].name),
)).toBeInTheDocument();

await waitFor(() => {
userEvent.click(getByText(messages.newLocationButton.defaultMessage));
expect(mockedUsedNavigate).toHaveBeenCalledWith(`/course/${courseId}/container/${iframePostMsg.data.params.targetParentLocator}`);
});
});

it('should display move cancellation alert when undo move button is clicked', async () => {
const {
getByRole,
getAllByLabelText,
getByText,
} = render(<RootWrapper />);

const iframePostMsg = getIFramePostMessages('move_xblock');

axiosMock
.onGet(getCourseVerticalChildrenApiUrl(blockId))
.reply(200, courseVerticalChildrenMock);

await executeThunk(fetchCourseVerticalChildrenData(blockId), store.dispatch);

const [xblockActionBtn] = getAllByLabelText(courseXBlockMessages.blockActionsDropdownAlt.defaultMessage);
userEvent.click(xblockActionBtn);

const xblockMoveBtn = getByRole('button', { name: courseXBlockMessages.blockLabelButtonMove.defaultMessage });
userEvent.click(xblockMoveBtn);

await act(async () => window.dispatchEvent(new MessageEvent('message', iframePostMsg)));

await waitFor(() => userEvent.click(getByText(messages.undoMoveButton.defaultMessage)));

axiosMock
.onPatch(postXBlockBaseApiUrl(), {
parent_locator: blockId,
move_source_locator: courseVerticalChildrenMock.children[0].block_id,
})
.reply(200, {
parent_locator: blockId,
move_source_locator: courseVerticalChildrenMock.children[0].block_id,
});

await executeThunk(rollbackUnitItemQuery(blockId, courseVerticalChildrenMock.children[0].block_id, 'Discussion'), store.dispatch);

expect(getByText(messages.alertMoveCancelTitle.defaultMessage)).toBeInTheDocument();
expect(getByText(
messages.alertMoveCancelDescription.defaultMessage
.replace('{title}', courseVerticalChildrenMock.children[0].name),
)).toBeInTheDocument();
});
});
});
20 changes: 16 additions & 4 deletions src/course-unit/course-xblock/CourseXBlock.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ const CourseXBlock = memo(({

useEffect(() => {
const handleMessage = (event) => {
const { method } = event.data;
const { method, params } = event.data;

if (method === 'close_edit_modal') {
toggleLegacyEditModal(false);
Expand All @@ -97,8 +97,14 @@ const CourseXBlock = memo(({
dispatch(fetchCourseVerticalChildrenData(blockId));
dispatch(fetchXBlockIFrameHtmlAndResourcesQuery(id));
dispatch(fetchCourseUnitQuery(blockId));
} else if (method === 'moving_xblock') {
dispatch(updateMovedXBlockParams({ title, isSuccess: true, sourceLocator: id }));
} else if (method === 'move_xblock') {
toggleLegacyMoveModal(false);
dispatch(updateMovedXBlockParams({
title: params.sourceDisplayName,
isSuccess: true,
sourceLocator: params.sourceLocator,
targetParentLocator: params.targetParentLocator,
}));
window.scrollTo({ top: 0, behavior: 'smooth' });
}
};
Expand Down Expand Up @@ -162,7 +168,13 @@ const CourseXBlock = memo(({

const handleXBlockMove = () => {
toggleLegacyMoveModal(true);
dispatch(updateMovedXBlockParams({ isSuccess: false }));
dispatch(updateMovedXBlockParams({
isSuccess: false,
isUndo: false,
title: '',
sourceLocator: '',
targetParentLocator: '',
}));
};

const onConfigureSubmit = (...arg) => {
Expand Down
6 changes: 3 additions & 3 deletions src/course-unit/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,14 +155,14 @@ export async function duplicateUnitItem(itemId, XBlockId) {
/**
* Rolls back a unit item to its previous state.
* @param {string} itemId - The ID of the item to be rolled back.
* @param {string} XBlockId - The ID of the XBlock associated with the item.
* @param {string} xblockId - The ID of the XBlock associated with the item.
* @returns {Promise<any>} - A promise that resolves to the response data from the server.
*/
export async function rollbackUnitItem(itemId, XBlockId) {
export async function rollbackUnitItem(itemId, xblockId) {
const { data } = await getAuthenticatedHttpClient()
.patch(postXBlockBaseApiUrl(), {
parent_locator: itemId,
move_source_locator: XBlockId,
move_source_locator: xblockId,
});

return data;
Expand Down
1 change: 1 addition & 0 deletions src/course-unit/data/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const slice = createSlice({
isUndo: false,
title: '',
sourceLocator: '',
targetParentLocator: '',
},
loadingStatus: {
fetchUnitLoadingStatus: RequestStatus.IN_PROGRESS,
Expand Down
5 changes: 5 additions & 0 deletions src/course-unit/hooks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ export const useCourseUnit = ({ courseId, blockId }) => {
dispatch(updateMovedXBlockParams({ isSuccess: false }));
};

const handleNavigateToTargetUnit = () => {
navigate(`/course/${courseId}/container/${movedXBlockParams.targetParentLocator}`);
};

useEffect(() => {
if (savingStatus === RequestStatus.SUCCESSFUL) {
dispatch(updateQueryPendingStatus(true));
Expand Down Expand Up @@ -180,6 +184,7 @@ export const useCourseUnit = ({ courseId, blockId }) => {
handleRollbackMovedXBlock,
handleCloseXBlockMovedAlert,
movedXBlockParams,
handleNavigateToTargetUnit,
canPasteComponent,
};
};
4 changes: 4 additions & 0 deletions src/course-unit/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ const messages = defineMessages({
id: 'course-authoring.course-unit.alert.xblock.move.undo.btn.text',
defaultMessage: 'Undo move',
},
newLocationButton: {
id: 'course-authoring.course-unit.alert.xblock.new.location.btn.text',
defaultMessage: 'Take me to the new location',
},
});

export default messages;

0 comments on commit 0583d90

Please sign in to comment.