diff --git a/frontend/src/bundles/studio/helpers/helpers.ts b/frontend/src/bundles/studio/helpers/helpers.ts index df8630b95..ab1113d36 100644 --- a/frontend/src/bundles/studio/helpers/helpers.ts +++ b/frontend/src/bundles/studio/helpers/helpers.ts @@ -4,4 +4,5 @@ export { getNewItemIndexBySpan } from './get-new-item-index.js'; export { calculateTotalMilliseconds } from './get-total-time.js'; export { getVoicesConfigs } from './get-voices-configs.helper.js'; export { reorderItemsByIndexes } from './reorder-items.js'; +export { scenesExceedScripts } from './scenes-exceed-scripts.js'; export { setItemsSpan } from './set-items-span.js'; diff --git a/frontend/src/bundles/studio/helpers/scenes-exceed-scripts.ts b/frontend/src/bundles/studio/helpers/scenes-exceed-scripts.ts new file mode 100644 index 000000000..06621a128 --- /dev/null +++ b/frontend/src/bundles/studio/helpers/scenes-exceed-scripts.ts @@ -0,0 +1,18 @@ +import { type Scene, type Script } from '../types/types.js'; + +const INITIAL_DURATION = 0; + +const scenesExceedScripts = (scenes: Scene[], scripts: Script[]): boolean => { + const totalScenesDuration = scenes.reduce( + (accumulator, scene) => accumulator + scene.duration, + INITIAL_DURATION, + ); + const totalScriptsDuration = scripts.reduce( + (accumulator, script) => accumulator + script.duration, + INITIAL_DURATION, + ); + + return totalScenesDuration > totalScriptsDuration; +}; + +export { scenesExceedScripts }; diff --git a/frontend/src/bundles/studio/pages/studio.tsx b/frontend/src/bundles/studio/pages/studio.tsx index 1fbf71ef2..3aabb1eb8 100644 --- a/frontend/src/bundles/studio/pages/studio.tsx +++ b/frontend/src/bundles/studio/pages/studio.tsx @@ -23,6 +23,7 @@ import { useLocation, useNavigate, useRef, + useState, } from '~/bundles/common/hooks/hooks.js'; import { IconName } from '~/bundles/common/icons/icons.js'; import { notificationService } from '~/bundles/common/services/services.js'; @@ -33,6 +34,7 @@ import { Timeline, VideoMenu, VideoNameInput, + WarningModal, } from '../components/components.js'; import { SCRIPT_AND_AVATAR_ARE_REQUIRED, @@ -42,12 +44,13 @@ import { VIDEO_SUBMIT_NOTIFICATION_ID, } from '../constants/constants.js'; import { NotificationMessage, NotificationTitle } from '../enums/enums.js'; -import { getVoicesConfigs } from '../helpers/helpers.js'; +import { getVoicesConfigs, scenesExceedScripts } from '../helpers/helpers.js'; import { selectVideoDataById } from '../store/selectors.js'; import { actions as studioActions } from '../store/studio.js'; const Studio: React.FC = () => { const { state: locationState } = useLocation(); + const [isModalOpen, setIsModalOpen] = useState(false); const videoData = useAppSelector((state) => selectVideoDataById(state, locationState?.id), @@ -60,6 +63,14 @@ const Studio: React.FC = () => { const dispatch = useAppDispatch(); const navigate = useNavigate(); + const handleOpenModal = useCallback(() => { + setIsModalOpen(true); + }, []); + + const handleCloseModal = useCallback(() => { + setIsModalOpen(false); + }, []); + useEffect((): void => { if (videoData) { void dispatch(studioActions.loadVideoData(videoData)); @@ -70,11 +81,10 @@ const Studio: React.FC = () => { dispatch(studioActions.changeVideoSize()); }, [dispatch]); - const handleSubmit = useCallback(() => { + const handleConfirmSubmit = useCallback(() => { // TODO: REPLACE LOGIC WITH MULTIPLE SCENES const scene = scenes[0]; const script = scripts[0]; - if (!scene?.avatar || !script) { notificationService.warn({ id: SCRIPT_AND_AVATAR_ARE_REQUIRED, @@ -106,6 +116,14 @@ const Studio: React.FC = () => { }); }, [dispatch, navigate, scenes, scripts]); + const handleSubmit = useCallback(() => { + if (scenesExceedScripts(scenes, scripts)) { + handleOpenModal(); + } else { + handleConfirmSubmit(); + } + }, [handleConfirmSubmit, handleOpenModal, scenes, scripts]); + useEffect(() => { return () => { dispatch(studioActions.resetStudio()); @@ -171,6 +189,11 @@ const Studio: React.FC = () => { display="flex" flexDirection="column" > +