Skip to content

Commit

Permalink
refactor: edit modal functional
Browse files Browse the repository at this point in the history
  • Loading branch information
PKulkoRaccoonGang committed Nov 5, 2024
1 parent 2723858 commit 7c3ca82
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 65 deletions.
16 changes: 0 additions & 16 deletions src/course-unit/CourseUnit.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,3 @@
.course-unit__alert {
margin-bottom: 1.75rem;
}

.modal-window-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #000;
opacity: 0.5;
z-index: 1000;
}

iframe {
z-index: 99999999999999;
position: relative;
}
4 changes: 3 additions & 1 deletion src/course-unit/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,12 @@ export const messageTypes = {
manageXBlockAccess: 'manageXBlockAccess',
deleteXBlock: 'deleteXBlock',
duplicateXBlock: 'duplicateXBlock',
refreshPositions: 'refreshPositions',
newXBlockEditor: 'newXBlockEditor',
showXBlockEditorModal: 'showXBlockEditorModal',
hideXBlockEditorModal: 'hideXBlockEditorModal',
editXBlock: 'editXBlock',
closeXBlockEditorModal: 'closeXBlockEditorModal',
saveEditedXBlockData: 'saveEditedXBlockData',
};

export const IFRAME_FEATURE_POLICY = (
Expand Down
79 changes: 31 additions & 48 deletions src/course-unit/xblock-container-iframe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import { useNavigate } from 'react-router-dom';

import DeleteModal from '../../generic/delete-modal/DeleteModal';
import ConfigureModal from '../../generic/configure-modal/ConfigureModal';
import ModalIframe from '../../generic/modal-iframe/ModalIframe';
import { copyToClipboard } from '../../generic/data/thunks';
import { COURSE_BLOCK_NAMES } from '../../constants';
import { IFRAME_FEATURE_POLICY, messageTypes } from '../constants';
import { fetchCourseUnitQuery } from '../data/thunk';
import { useIframe } from '../context/hooks';
import { useIFrameBehavior } from './hooks';
import messages from './messages';
Expand Down Expand Up @@ -76,21 +76,15 @@ const XBlockContainerIframe: FC<XBlockContainerIframeProps> = ({
const { setIframeRef, sendMessageToIframe } = useIframe();
const [editXblockId, setEditXblockId] = useState<string | null>(null);
const [currentXblockData, setCurrentXblockData] = useState<any>({});
const [showOverlay, setShowOverlay] = useState(false);
const [scrollPosition, setScrollPosition] = useState(0);
const [showLegacyEditModal, setShowLegacyEditModal] = useState(false);

const iframeUrl = `${getConfig().STUDIO_BASE_URL}/container_embed/${blockId}`;
const editXBlockModalUrl = `${getConfig().STUDIO_BASE_URL}/xblock/${editXblockId}/actions/edit`;

useEffect(() => {
setIframeRef(iframeRef);
}, [setIframeRef]);

useEffect(() => {
sendMessageToIframe('controlEditModalPosition', {
height: scrollPosition,
});
}, [scrollPosition]);

const handleDelete = (id: string) => {
openDeleteModal();
setDeleteXblockId(id);
Expand All @@ -114,60 +108,54 @@ const XBlockContainerIframe: FC<XBlockContainerIframeProps> = ({
}
};

document.addEventListener('scroll', () => {
setScrollPosition(window.scrollY - 200);
});

const handleCopy = (id: string) => {
dispatch(copyToClipboard(id));
};

const handleDuplicateXBlock = (id) => {
if (id) {
unitXBlockActions.handleDuplicate(id);
// TODO: this artificial delay is a temporary solution
// to ensure the iframe content is properly refreshed.
setTimeout(() => {
sendMessageToIframe(messageTypes.refreshXBlock, null);
}, 1000);
}
};

const handleRefreshXBlocks = () => {
// TODO: this artificial delay is a temporary solution
// to ensure the iframe content is properly refreshed.
setTimeout(() => {
dispatch(fetchCourseUnitQuery(blockId));
sendMessageToIframe(messageTypes.refreshXBlock, null);
}, 1000);
};

const handleDuplicateXBlock = (id) => {
if (id) {
unitXBlockActions.handleDuplicate(id);
handleRefreshXBlocks();
}
};

const navigateToNewXBlockEditor = (url: string) => {
navigate(`/course/${courseId}/editor${url}`);
};

const handleShowEditXBlockModal = (id: string) => {
setEditXblockId(id);
setShowLegacyEditModal(true);
};

const handleCloseEditorXBlockModal = () => {
setEditXblockId(null);
setShowLegacyEditModal(false);
};

useEffect(() => {
const messageHandlers: Record<string, (payload) => void> = {
[messageTypes.deleteXBlock]: (payload) => handleDelete(payload.id),
[messageTypes.manageXBlockAccess]: (payload) => handleConfigure(payload.id),
[messageTypes.copyXBlock]: (payload) => handleCopy(payload.id),
[messageTypes.duplicateXBlock]: (payload) => handleDuplicateXBlock(payload.id),
[messageTypes.refreshPositions]: handleRefreshXBlocks,
[messageTypes.newXBlockEditor]: (payload) => navigateToNewXBlockEditor(payload.url),
[messageTypes.editXBlock]: (payload) => handleShowEditXBlockModal(payload.id),
[messageTypes.closeXBlockEditorModal]: () => handleCloseEditorXBlockModal(),
[messageTypes.saveEditedXBlockData]: handleRefreshXBlocks,
};

const handleMessage = (event: MessageEvent) => {
const { type, payload } = event.data || {};

if (type === messageTypes.showXBlockEditorModal) {
setShowOverlay(true);
// document.body.style.overflow = 'hidden';
}

if (type === messageTypes.hideXBlockEditorModal) {
setShowOverlay(false);
// document.body.style.overflow = 'auto';
}

if (type && messageHandlers[type]) {
messageHandlers[type](payload);
}
Expand All @@ -189,29 +177,24 @@ const XBlockContainerIframe: FC<XBlockContainerIframeProps> = ({
if (deleteXblockId) {
unitXBlockActions.handleDelete(deleteXblockId);
closeDeleteModal();
// TODO: this artificial delay is a temporary solution
// to ensure the iframe content is properly refreshed.
setTimeout(() => {
sendMessageToIframe(messageTypes.refreshXBlock, null);
}, 1000);
handleRefreshXBlocks();
}
};

const onConfigureSubmit = (...args: any[]) => {
if (editXblockId) {
handleConfigureSubmit(editXblockId, ...args, closeConfigureModal);
// TODO: this artificial delay is a temporary solution
// to ensure the iframe content is properly refreshed.
setTimeout(() => {
sendMessageToIframe(messageTypes.refreshXBlock, null);
}, 1000);
handleRefreshXBlocks();
}
};

return (
<>
{showOverlay && (
<div className="modal-window-overlay" />
{showLegacyEditModal && (
<ModalIframe
title="XBlock Edit Modal"
src={editXBlockModalUrl}
/>
)}
<DeleteModal
category="component"
Expand Down
13 changes: 13 additions & 0 deletions src/generic/modal-iframe/ModalIframe.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.modal-iframe {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: $zindex-modal;

iframe {
width: inherit;
height: inherit;
}
}
44 changes: 44 additions & 0 deletions src/generic/modal-iframe/ModalIframe.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { forwardRef, ForwardedRef, IframeHTMLAttributes } from 'react';
import classNames from 'classnames';

interface ModalIframeProps extends IframeHTMLAttributes<HTMLIFrameElement> {
title: string;
className?: string;
}

const SANDBOX_OPTIONS = [
'allow-forms',
'allow-modals',
'allow-popups',
'allow-popups-to-escape-sandbox',
'allow-presentation',
'allow-same-origin',
'allow-scripts',
'allow-top-navigation-by-user-activation',
].join(' ');

export const IFRAME_FEATURE_POLICY = (
'microphone *; camera *; midi *; geolocation *; encrypted-media *, clipboard-write *'
);

const ModalIframe = forwardRef<HTMLIFrameElement, ModalIframeProps>(
({ title, className, ...props }, ref: ForwardedRef<HTMLIFrameElement>) => (
<iframe
title={title}
className={classNames('modal-iframe', className)}
allow={IFRAME_FEATURE_POLICY}
referrerPolicy="origin"
frameBorder="0"
scrolling="no"
ref={ref}
sandbox={SANDBOX_OPTIONS}
{...props}
/>
),
);

ModalIframe.defaultProps = {
className: 'modal-iframe',
};

export default ModalIframe;
1 change: 1 addition & 0 deletions src/generic/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
@import "./configure-modal/ConfigureModal";
@import "./drag-helper/SortableItem";
@import "./block-type-utils";
@import "./modal-iframe/ModalIframe"

0 comments on commit 7c3ca82

Please sign in to comment.