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"
>
+