From 8fdc0404bf8ffc7bf29b1d8c06d8cf6fa0c10d15 Mon Sep 17 00:00:00 2001 From: PKulkoRaccoonGang Date: Mon, 29 Apr 2024 21:31:42 +0300 Subject: [PATCH] feat: added alert logic --- src/course-unit/CourseUnit.jsx | 25 ++++++++++++------- .../course-xblock/CourseXBlock.jsx | 5 +++- src/course-unit/data/api.js | 10 ++++++++ src/course-unit/data/selectors.js | 3 +++ src/course-unit/data/slice.js | 11 ++++++++ src/course-unit/data/thunk.js | 22 +++++++++++++++- src/course-unit/hooks.jsx | 17 ++++++++++++- 7 files changed, 81 insertions(+), 12 deletions(-) diff --git a/src/course-unit/CourseUnit.jsx b/src/course-unit/CourseUnit.jsx index cadcea91b2..2076573fc6 100644 --- a/src/course-unit/CourseUnit.jsx +++ b/src/course-unit/CourseUnit.jsx @@ -1,6 +1,6 @@ import React, { useEffect, useMemo, useState } from 'react'; import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; import { Container, Layout, Stack, Button, TransitionReplace, @@ -37,6 +37,8 @@ import PublishControls from './sidebar/PublishControls'; import LocationInfo from './sidebar/LocationInfo'; import TagsSidebarControls from '../content-tags-drawer/tags-sidebar-controls'; import { PasteNotificationAlert } from './clipboard'; +import { updateIsBlockMovedData } from 'CourseAuthoring/course-unit/data/slice'; +import { rollbackUnitItemQuery } from 'CourseAuthoring/course-unit/data/thunk'; const CourseUnit = ({ courseId }) => { const { blockId } = useParams(); @@ -67,8 +69,11 @@ const CourseUnit = ({ courseId }) => { isXBlocksExpanded, isXBlocksRendered, handleExpandAll, + handleCourseUnitRollbackMovedXBlock, + isBlockMovedSuccess, + movedXBlockTitle, } = useCourseUnit({ courseId, blockId }); - + const dispatch = useDispatch(); const initialXBlocksData = useMemo(() => courseVerticalChildren.children ?? [], [courseVerticalChildren.children]); const [unitXBlocks, setUnitXBlocks] = useState(initialXBlocksData); @@ -112,21 +117,23 @@ const CourseUnit = ({ courseId }) => {
- {true ? ( + {isBlockMovedSuccess ? ( diff --git a/src/course-unit/course-xblock/CourseXBlock.jsx b/src/course-unit/course-xblock/CourseXBlock.jsx index d8cf10f46f..1ca73494c0 100644 --- a/src/course-unit/course-xblock/CourseXBlock.jsx +++ b/src/course-unit/course-xblock/CourseXBlock.jsx @@ -38,6 +38,7 @@ import { fetchCourseVerticalChildrenData, fetchXBlockIFrameHtmlAndResourcesQuery, } from '../data/thunk'; +import { updateIsBlockMovedData } from '../data/slice'; import { COMPONENT_TYPES } from '../constants'; import XBlockMessages from './xblock-messages/XBlockMessages'; import RenderErrorAlert from './render-error-alert'; @@ -86,7 +87,7 @@ const CourseXBlock = memo(({ useEffect(() => { const handleMessage = (event) => { const { method } = event.data; - + console.log('METHOD =======>', method); if (method === 'close_edit_modal') { toggleLegacyEditModal(false); dispatch(fetchCourseVerticalChildrenData(blockId)); @@ -97,6 +98,8 @@ const CourseXBlock = memo(({ dispatch(fetchCourseVerticalChildrenData(blockId)); dispatch(fetchXBlockIFrameHtmlAndResourcesQuery(id)); dispatch(fetchCourseUnitQuery(blockId)); + } else if (method === 'xblock_moved') { + dispatch(updateIsBlockMovedData({ title, show: true, locator: id })); } }; diff --git a/src/course-unit/data/api.js b/src/course-unit/data/api.js index a56f1892a8..ae432d8bd6 100644 --- a/src/course-unit/data/api.js +++ b/src/course-unit/data/api.js @@ -152,6 +152,16 @@ export async function duplicateUnitItem(itemId, XBlockId) { return data; } +export async function rollbackUnitItem(itemId, XBlockId) { + const { data } = await getAuthenticatedHttpClient() + .patch(postXBlockBaseApiUrl(), { + parent_locator: itemId, + move_source_locator: XBlockId, + }); + + return data; +} + /** * Sets the order list of XBlocks. * @param {string} blockId - The identifier of the course unit. diff --git a/src/course-unit/data/selectors.js b/src/course-unit/data/selectors.js index 34b889a365..3841cf3be3 100644 --- a/src/course-unit/data/selectors.js +++ b/src/course-unit/data/selectors.js @@ -15,6 +15,9 @@ export const getSequenceId = (state) => state.courseUnit.sequenceId; export const getCourseVerticalChildren = (state) => state.courseUnit.courseVerticalChildren; export const getCsrfTokenData = (state) => state.courseUnit.csrfToken; const getLoadingStatuses = (state) => state.courseUnit.loadingStatus; +export const getIsBlockMovedSuccess = (state) => state.courseUnit.xblockMoveParams.isBlockMovedSuccess; +export const getMovedXBlockTitle = (state) => state.courseUnit.xblockMoveParams.movedXBlockTitle; +export const getXBlockSourseLocator = (state) => state.courseUnit.xblockMoveParams.xblockSourseLocator; export const getXBlockIFrameHtmlAndResources = (state) => state.courseUnit.xblockIFrameHtmlAndResources; export const getIsLoading = createSelector( [getLoadingStatuses], diff --git a/src/course-unit/data/slice.js b/src/course-unit/data/slice.js index e46f35efce..eca3dcb376 100644 --- a/src/course-unit/data/slice.js +++ b/src/course-unit/data/slice.js @@ -11,6 +11,11 @@ const slice = createSlice({ csrfToken: '', isQueryPending: false, isTitleEditFormOpen: false, + xblockMoveParams: { + isBlockMovedSuccess: false, + movedXBlockTitle: '', + xblockSourseLocator: '', + }, loadingStatus: { fetchUnitLoadingStatus: RequestStatus.IN_PROGRESS, courseSectionVerticalLoadingStatus: RequestStatus.IN_PROGRESS, @@ -35,6 +40,11 @@ const slice = createSlice({ updateQueryPendingStatus: (state, { payload }) => { state.isQueryPending = payload; }, + updateIsBlockMovedData: (state, { payload }) => { + state.xblockMoveParams.isBlockMovedSuccess = payload.show; + state.xblockMoveParams.movedXBlockTitle = payload.title; + state.xblockMoveParams.xblockSourseLocator = payload.locator; + }, changeEditTitleFormOpen: (state, { payload }) => { state.isTitleEditFormOpen = payload; }, @@ -140,6 +150,7 @@ export const { reorderXBlockList, fetchXBlockIFrameResources, fetchCsrfTokenSuccess, + updateIsBlockMovedData, } = slice.actions; export const { diff --git a/src/course-unit/data/thunk.js b/src/course-unit/data/thunk.js index f934b19042..55f55ccf4d 100644 --- a/src/course-unit/data/thunk.js +++ b/src/course-unit/data/thunk.js @@ -21,7 +21,7 @@ import { duplicateUnitItem, setXBlockOrderList, getXBlockIFrameData, - getCsrfTokenData, + getCsrfTokenData, rollbackUnitItem, } from './api'; import { updateLoadingCourseUnitStatus, @@ -254,6 +254,26 @@ export function duplicateUnitItemQuery(itemId, xblockId) { }; } +export function rollbackUnitItemQuery(itemId, xblockId) { + return async (dispatch) => { + dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); + dispatch(showProcessingNotification(NOTIFICATION_MESSAGES.duplicating)); + + try { + await rollbackUnitItem(itemId, xblockId); + const newCourseVerticalChildren = await getCourseVerticalChildren(itemId); + dispatch(updateCourseVerticalChildren(newCourseVerticalChildren)); + const courseUnit = await getCourseUnitData(itemId); + dispatch(fetchCourseItemSuccess(courseUnit)); + dispatch(hideProcessingNotification()); + dispatch(updateSavingStatus({ status: RequestStatus.SUCCESSFUL })); + } catch (error) { + dispatch(hideProcessingNotification()); + handleResponseErrors(error, dispatch, updateSavingStatus); + } + }; +} + export function setXBlockOrderListQuery(blockId, xblockListIds, restoreCallback) { return async (dispatch) => { dispatch(updateSavingStatus({ status: RequestStatus.PENDING })); diff --git a/src/course-unit/hooks.jsx b/src/course-unit/hooks.jsx index b5e0316982..3ffc1032c9 100644 --- a/src/course-unit/hooks.jsx +++ b/src/course-unit/hooks.jsx @@ -16,6 +16,7 @@ import { editCourseUnitVisibilityAndData, setXBlockOrderListQuery, fetchCsrfTokenQuery, + rollbackUnitItemQuery, } from './data/thunk'; import { getCourseSectionVertical, @@ -27,8 +28,11 @@ import { getSequenceStatus, getStaticFileNotices, getIsLoadingFailed, + getIsBlockMovedSuccess, + getMovedXBlockTitle, + getXBlockSourseLocator, } from './data/selectors'; -import { changeEditTitleFormOpen, updateQueryPendingStatus } from './data/slice'; +import { changeEditTitleFormOpen, updateIsBlockMovedData, updateQueryPendingStatus } from './data/slice'; import { PUBLISH_TYPES } from './constants'; import { useCopyToClipboard } from '../generic/clipboard'; @@ -44,6 +48,9 @@ export const useCourseUnit = ({ courseId, blockId }) => { const isLoading = useSelector(getIsLoading); const isLoadingFailed = useSelector(getIsLoadingFailed); const errorMessage = useSelector(getErrorMessage); + const isBlockMovedSuccess = useSelector(getIsBlockMovedSuccess); + const movedXBlockTitle = useSelector(getMovedXBlockTitle); + const xblockSourseLocator = useSelector(getXBlockSourseLocator); const sequenceStatus = useSelector(getSequenceStatus); const { draftPreviewLink, publishedPreviewLink } = useSelector(getCourseSectionVertical); const courseVerticalChildren = useSelector(getCourseVerticalChildren); @@ -111,6 +118,11 @@ export const useCourseUnit = ({ courseId, blockId }) => { setXBlocksExpanded((prevState) => !prevState); }; + const handleCourseUnitRollbackMovedXBlock = () => { + dispatch(rollbackUnitItemQuery(blockId, xblockSourseLocator)); + dispatch(updateIsBlockMovedData({ show: false })); + }; + useEffect(() => { if (savingStatus === RequestStatus.SUCCESSFUL) { dispatch(updateQueryPendingStatus(true)); @@ -152,5 +164,8 @@ export const useCourseUnit = ({ courseId, blockId }) => { isXBlocksExpanded, isXBlocksRendered, handleExpandAll, + handleCourseUnitRollbackMovedXBlock, + isBlockMovedSuccess, + movedXBlockTitle, }; };