// @ts-check
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
Button,
Container,
Layout,
Row,
TransitionReplace,
} from '@openedx/paragon';
import { Helmet } from 'react-helmet';
import {
Add as IconAdd,
CheckCircle as CheckCircleIcon,
Warning as WarningIcon,
} from '@openedx/paragon/icons';
import { useSelector } from 'react-redux';
import {
arrayMove,
SortableContext,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { LoadingSpinner } from '../generic/Loading';
import { getProcessingNotification } from '../generic/processing-notification/data/selectors';
import { RequestStatus } from '../data/constants';
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 AlertMessage from '../generic/alert-message';
import getPageHeadTitle from '../generic/utils';
import { getCurrentItem } from './data/selectors';
import { COURSE_BLOCK_NAMES } from './constants';
import HeaderNavigations from './header-navigations/HeaderNavigations';
import OutlineSideBar from './outline-sidebar/OutlineSidebar';
import StatusBar from './status-bar/StatusBar';
import EnableHighlightsModal from './enable-highlights-modal/EnableHighlightsModal';
import SectionCard from './section-card/SectionCard';
import SubsectionCard from './subsection-card/SubsectionCard';
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 {
canMoveSection,
possibleUnitMoves,
possibleSubsectionMoves,
} from './drag-helper/utils';
import { useCourseOutline } from './hooks';
import messages from './messages';
const CourseOutline = ({ courseId }) => {
const intl = useIntl();
const {
courseName,
savingStatus,
statusBarData,
courseActions,
sectionsList,
isCustomRelativeDatesActive,
isLoading,
isReIndexShow,
showErrorAlert,
showSuccessAlert,
isSectionsExpanded,
isEnableHighlightsModalOpen,
isInternetConnectionAlertFailed,
isDisabledReindexButton,
isHighlightsModalOpen,
isPublishModalOpen,
isConfigureModalOpen,
isDeleteModalOpen,
closeHighlightsModal,
closePublishModal,
handleConfigureModalClose,
closeDeleteModal,
openPublishModal,
openConfigureModal,
openDeleteModal,
headerNavigationsActions,
openEnableHighlightsModal,
closeEnableHighlightsModal,
handleEnableHighlightsSubmit,
handleInternetConnectionFailed,
handleOpenHighlightsModal,
handleHighlightsFormSubmit,
handleConfigureItemSubmit,
handlePublishItemSubmit,
handleEditSubmit,
handleDeleteItemSubmit,
handleDuplicateSectionSubmit,
handleDuplicateSubsectionSubmit,
handleDuplicateUnitSubmit,
handleNewSectionSubmit,
handleNewSubsectionSubmit,
handleNewUnitSubmit,
getUnitUrl,
handleVideoSharingOptionChange,
handleCopyToClipboardClick,
handlePasteClipboardClick,
notificationDismissUrl,
discussionsSettings,
discussionsIncontextFeedbackUrl,
discussionsIncontextLearnmoreUrl,
deprecatedBlocksInfo,
proctoringErrors,
mfeProctoredExamSettingsUrl,
handleDismissNotification,
advanceSettingsUrl,
handleSectionDragAndDrop,
handleSubsectionDragAndDrop,
handleUnitDragAndDrop,
} = useCourseOutline({ courseId });
const [sections, setSections] = useState(sectionsList);
const restoreSectionList = () => {
setSections(() => [...sectionsList]);
};
const {
isShow: isShowProcessingNotification,
title: processingNotificationTitle,
} = useSelector(getProcessingNotification);
const { category } = useSelector(getCurrentItem);
const deleteCategory = COURSE_BLOCK_NAMES[category]?.name.toLowerCase();
/**
* Move section to new index
* @param {any} currentIndex
* @param {any} newIndex
*/
const updateSectionOrderByIndex = (currentIndex, newIndex) => {
if (currentIndex === newIndex) {
return;
}
setSections((prevSections) => {
const newSections = arrayMove(prevSections, currentIndex, newIndex);
handleSectionDragAndDrop(newSections.map(section => section.id));
return newSections;
});
};
/**
* Uses details from move information and moves subsection
* @param {any} section
* @param {any} moveDetails
* @returns {void}
*/
const updateSubsectionOrderByIndex = (section, moveDetails) => {
const { fn, args, sectionId } = moveDetails;
if (!args) {
return;
}
const [sectionsCopy, newSubsections] = fn(...args);
if (newSubsections && sectionId) {
setSections(sectionsCopy);
handleSubsectionDragAndDrop(
sectionId,
section.id,
newSubsections.map(subsection => subsection.id),
restoreSectionList,
);
}
};
/**
* Uses details from move information and moves unit
* @param {any} section
* @param {any} moveDetails
* @returns {void}
*/
const updateUnitOrderByIndex = (section, moveDetails) => {
const {
fn, args, sectionId, subsectionId,
} = moveDetails;
if (!args) {
return;
}
const [sectionsCopy, newUnits] = fn(...args);
if (newUnits && sectionId && subsectionId) {
setSections(sectionsCopy);
handleUnitDragAndDrop(
sectionId,
section.id,
subsectionId,
newUnits.map(unit => unit.id),
restoreSectionList,
);
}
};
useEffect(() => {
setSections(sectionsList);
}, [sectionsList]);
if (isLoading) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return (