Skip to content

Commit

Permalink
feat: [FC-0070] rendering split test content in unit page
Browse files Browse the repository at this point in the history
  • Loading branch information
ihor-romaniuk committed Nov 12, 2024
1 parent 89a6473 commit 8e41ceb
Show file tree
Hide file tree
Showing 22 changed files with 454 additions and 147 deletions.
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export const COURSE_BLOCK_NAMES = ({
sequential: { id: 'sequential', name: 'Subsection' },
vertical: { id: 'vertical', name: 'Unit' },
libraryContent: { id: 'library_content', name: 'Library content' },
splitTest: { id: 'split_test', name: 'Split Test' },
component: { id: 'component', name: 'Component' },
});

Expand Down
26 changes: 19 additions & 7 deletions src/course-unit/CourseUnit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import Breadcrumbs from './breadcrumbs/Breadcrumbs';
import HeaderNavigations from './header-navigations/HeaderNavigations';
import Sequence from './course-sequence';
import Sidebar from './sidebar';
import SplitTestSidebarInfo from './sidebar/SplitTestSidebarInfo';
import { useCourseUnit } from './hooks';
import messages from './messages';
import PublishControls from './sidebar/PublishControls';
Expand Down Expand Up @@ -68,10 +69,14 @@ const CourseUnit = ({ courseId }) => {
handleRollbackMovedXBlock,
handleCloseXBlockMovedAlert,
handleNavigateToTargetUnit,
addComponentTemplateData,
setAddComponentTemplateData,
handleSubmitAddComponentModal,
} = useCourseUnit({ courseId, blockId });

const isUnitVerticalType = unitCategory === COURSE_BLOCK_NAMES.vertical.id;
const isUnitLibraryType = unitCategory === COURSE_BLOCK_NAMES.libraryContent.id;
const isSplitTestType = unitCategory === COURSE_BLOCK_NAMES.splitTest.id;

const unitLayout = [{ span: 12 }, { span: 0 }];
const defaultLayout = {
Expand Down Expand Up @@ -161,7 +166,7 @@ const CourseUnit = ({ courseId }) => {
)}
headerActions={(
<HeaderNavigations
unitCategory={unitCategory}
category={unitCategory}
headerNavigationsActions={headerNavigationsActions}
/>
)}
Expand Down Expand Up @@ -192,12 +197,14 @@ const CourseUnit = ({ courseId }) => {
/>
)}
<XBlockContainerIframe blockId={blockId} />
{isUnitVerticalType && (
<AddComponent
blockId={blockId}
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
/>
)}
<AddComponent
isUnitVerticalType={isUnitVerticalType}
parentLocator={blockId}
handleCreateNewCourseXBlock={handleCreateNewCourseXBlock}
handleSubmitAddComponentModal={handleSubmitAddComponentModal}
addComponentTemplateData={addComponentTemplateData}
setAddComponentTemplateData={setAddComponentTemplateData}
/>
{showPasteXBlock && canPasteComponent && isUnitVerticalType && (
<PasteComponent
clipboardData={sharedClipboardData}
Expand Down Expand Up @@ -229,6 +236,11 @@ const CourseUnit = ({ courseId }) => {
</Sidebar>
</>
)}
{isSplitTestType && (
<Sidebar data-testid="course-split-test-sidebar">
<SplitTestSidebarInfo />
</Sidebar>
)}
</Stack>
</Layout.Element>
</Layout>
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 @@ -4,6 +4,7 @@
@import "./sidebar/Sidebar";
@import "./header-title/HeaderTitle";
@import "./move-modal";
@import "./xblock-container-iframe";

.course-unit {
min-width: 900px;
Expand Down
243 changes: 166 additions & 77 deletions src/course-unit/add-component/AddComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,121 +10,210 @@ import ComponentModalView from './add-component-modals/ComponentModalView';
import AddComponentButton from './add-component-btn';
import messages from './messages';

const AddComponent = ({ blockId, handleCreateNewCourseXBlock }) => {
const AddComponent = ({
parentLocator,
handleCreateNewCourseXBlock,
isUnitVerticalType,
handleSubmitAddComponentModal,
addComponentTemplateData,
setAddComponentTemplateData,
}) => {
const navigate = useNavigate();
const intl = useIntl();
const [isOpenAdvanced, openAdvanced, closeAdvanced] = useToggle(false);
const [isOpenHtml, openHtml, closeHtml] = useToggle(false);
const [isOpenOpenAssessment, openOpenAssessment, closeOpenAssessment] = useToggle(false);
const { componentTemplates = {} } = useSelector(getCourseSectionVertical);
const isRequestedModalView = addComponentTemplateData?.model?.type;
const blockId = addComponentTemplateData.parentLocator || parentLocator;

const handleCreateNewXBlock = (type, moduleName) => {
const preventDisplayLoading = isRequestedModalView && !isUnitVerticalType;
switch (type) {
case COMPONENT_TYPES.discussion:
case COMPONENT_TYPES.dragAndDrop:
handleCreateNewCourseXBlock({ type, parentLocator: blockId });
handleCreateNewCourseXBlock({
type,
parentLocator: blockId,
}, null, preventDisplayLoading);
break;
case COMPONENT_TYPES.problem:
case COMPONENT_TYPES.video:
handleCreateNewCourseXBlock({ type, parentLocator: blockId }, ({ courseKey, locator }) => {
navigate(`/course/${courseKey}/editor/${type}/${locator}`);
});
handleCreateNewCourseXBlock(
{
type,
parentLocator: blockId,
},
({ courseKey, locator }) => navigate(`/course/${courseKey}/editor/${type}/${locator}`),
preventDisplayLoading,
);
break;
// TODO: The library functional will be a bit different of current legacy (CMS)
// behaviour and this ticket is on hold (blocked by other development team).
case COMPONENT_TYPES.library:
handleCreateNewCourseXBlock({ type, category: 'library_content', parentLocator: blockId });
handleCreateNewCourseXBlock(
{
type,
category: 'library_content',
parentLocator: blockId,
},
null,
preventDisplayLoading,
);
break;
case COMPONENT_TYPES.advanced:
handleCreateNewCourseXBlock({
type: moduleName, category: moduleName, parentLocator: blockId,
});
handleCreateNewCourseXBlock(
{
type: moduleName,
category: moduleName,
parentLocator: blockId,
},
null,
preventDisplayLoading,
);
break;
case COMPONENT_TYPES.openassessment:
handleCreateNewCourseXBlock({
boilerplate: moduleName, category: type, parentLocator: blockId,
});
handleCreateNewCourseXBlock(
{
boilerplate: moduleName,
category:
type,
parentLocator: blockId,
},
null,
preventDisplayLoading,
);
break;
case COMPONENT_TYPES.html:
handleCreateNewCourseXBlock({
type,
boilerplate: moduleName,
parentLocator: blockId,
}, ({ courseKey, locator }) => {
navigate(`/course/${courseKey}/editor/html/${locator}`);
});
handleCreateNewCourseXBlock(
{
type,
boilerplate: moduleName,
parentLocator: blockId,
},
({ courseKey, locator }) => navigate(`/course/${courseKey}/editor/html/${locator}`),
preventDisplayLoading,
);
break;
default:
}
if (preventDisplayLoading) {
handleSubmitAddComponentModal();
}
};

if (!Object.keys(componentTemplates).length) {
return null;
if (isRequestedModalView && !isUnitVerticalType) {
return (
<ComponentModalView
isRequestedModalView
key={addComponentTemplateData.model.type}
component={addComponentTemplateData.model}
handleCreateNewXBlock={handleCreateNewXBlock}
modalParams={{
open: () => {},
close: () => setAddComponentTemplateData({}),
isOpen: addComponentTemplateData.model,
}}
/>
);
}

return (
<div className="py-4">
<h5 className="h3 mb-4 text-center">{intl.formatMessage(messages.title)}</h5>
<ul className="new-component-type list-unstyled m-0 d-flex flex-wrap justify-content-center">
{componentTemplates.map((component) => {
const { type, displayName } = component;
let modalParams;
if (Object.keys(componentTemplates).length && isUnitVerticalType) {
return (
<div className="py-4">
<h5 className="h3 mb-4 text-center">{intl.formatMessage(messages.title)}</h5>
<ul className="new-component-type list-unstyled m-0 d-flex flex-wrap justify-content-center">
{componentTemplates.map((component) => {
const { type, displayName } = component;
let modalParams;

if (!component.templates.length) {
return null;
}

if (!component.templates.length) {
return null;
}
switch (type) {
case COMPONENT_TYPES.advanced:
modalParams = {
open: openAdvanced,
close: closeAdvanced,
isOpen: isOpenAdvanced,
};
break;
case COMPONENT_TYPES.html:
modalParams = {
open: openHtml,
close: closeHtml,
isOpen: isOpenHtml,
};
break;
case COMPONENT_TYPES.openassessment:
modalParams = {
open: openOpenAssessment,
close: closeOpenAssessment,
isOpen: isOpenOpenAssessment,
};
break;
default:
return (
<li key={type}>
<AddComponentButton
onClick={() => handleCreateNewXBlock(type)}
displayName={displayName}
type={type}
/>
</li>
);
}

switch (type) {
case COMPONENT_TYPES.advanced:
modalParams = {
open: openAdvanced,
close: closeAdvanced,
isOpen: isOpenAdvanced,
};
break;
case COMPONENT_TYPES.html:
modalParams = {
open: openHtml,
close: closeHtml,
isOpen: isOpenHtml,
};
break;
case COMPONENT_TYPES.openassessment:
modalParams = {
open: openOpenAssessment,
close: closeOpenAssessment,
isOpen: isOpenOpenAssessment,
};
break;
default:
return (
<li key={type}>
<AddComponentButton
onClick={() => handleCreateNewXBlock(type)}
displayName={displayName}
type={type}
/>
</li>
);
}
return (
<ComponentModalView
key={type}
component={component}
handleCreateNewXBlock={handleCreateNewXBlock}
modalParams={modalParams}
/>
);
})}
</ul>
</div>
);
}

return null;
};

return (
<ComponentModalView
key={type}
component={component}
handleCreateNewXBlock={handleCreateNewXBlock}
modalParams={modalParams}
/>
);
})}
</ul>
</div>
);
AddComponent.defaultProps = {
addComponentTemplateData: {},
setAddComponentTemplateData: () => {},
};

AddComponent.propTypes = {
blockId: PropTypes.string.isRequired,
isUnitVerticalType: PropTypes.bool.isRequired,
parentLocator: PropTypes.string.isRequired,
handleCreateNewCourseXBlock: PropTypes.func.isRequired,
addComponentTemplateData: {
blockId: PropTypes.string.isRequired,
model: PropTypes.shape({
displayName: PropTypes.string.isRequired,
category: PropTypes.string,
type: PropTypes.string.isRequired,
templates: PropTypes.arrayOf(
PropTypes.shape({
boilerplateName: PropTypes.string,
category: PropTypes.string,
displayName: PropTypes.string.isRequired,
supportLevel: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
}),
),
supportLegend: PropTypes.shape({
allowUnsupportedXblocks: PropTypes.bool,
documentationLabel: PropTypes.string,
showLegend: PropTypes.bool,
}),
}),
},
setAddComponentTemplateData: PropTypes.func,
handleSubmitAddComponentModal: PropTypes.func.isRequired,
};

export default AddComponent;
Loading

0 comments on commit 8e41ceb

Please sign in to comment.