From cca244ffeada2cbd50dc3035731958145d353b11 Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Fri, 13 Sep 2024 23:07:25 -0400 Subject: [PATCH 01/18] OV-275: + initial step to manage sockets and update videos after ready state --- backend/package.json | 1 + .../avatar-videos/avatar-videos.service.ts | 10 + .../common/enums/avatar-video-event.enum.ts | 5 + backend/src/common/enums/enums.ts | 1 + .../server-application/base-server-app.ts | 14 ++ .../server-application/socket-application.ts | 11 + backend/src/common/socket/scoket-event.ts | 25 ++ backend/src/common/socket/socket.ts | 1 + frontend/package.json | 1 + frontend/src/bundles/common/context/socket.ts | 8 + .../common/enums/avatar-video-event.enum.ts | 5 + frontend/src/bundles/common/enums/enums.ts | 1 + frontend/src/bundles/common/hooks/hooks.ts | 1 + .../components/main-content/main-content.tsx | 17 +- frontend/src/index.tsx | 10 +- package-lock.json | 236 ++++++++++++++++++ 16 files changed, 343 insertions(+), 4 deletions(-) create mode 100644 backend/src/common/enums/avatar-video-event.enum.ts create mode 100644 backend/src/common/server-application/socket-application.ts create mode 100644 backend/src/common/socket/scoket-event.ts create mode 100644 backend/src/common/socket/socket.ts create mode 100644 frontend/src/bundles/common/context/socket.ts create mode 100644 frontend/src/bundles/common/enums/avatar-video-event.enum.ts diff --git a/backend/package.json b/backend/package.json index 448f633bb..63a1d9544 100644 --- a/backend/package.json +++ b/backend/package.json @@ -52,6 +52,7 @@ "pino": "9.3.2", "pino-pretty": "10.3.1", "shared": "*", + "socket.io": "4.7.5", "swagger-jsdoc": "6.2.8", "tiktoken": "1.0.16" } diff --git a/backend/src/bundles/avatar-videos/avatar-videos.service.ts b/backend/src/bundles/avatar-videos/avatar-videos.service.ts index 8c7f05260..e4ada65a5 100644 --- a/backend/src/bundles/avatar-videos/avatar-videos.service.ts +++ b/backend/src/bundles/avatar-videos/avatar-videos.service.ts @@ -1,8 +1,10 @@ import { HttpCode, HttpError } from 'shared'; import { v4 as uuidv4 } from 'uuid'; +import { AvatarVideoEvent } from '~/common/enums/enums.js'; import { type AzureAIService } from '~/common/services/azure-ai/azure-ai.service.js'; import { type FileService } from '~/common/services/file/file.service.js'; +import { socketEvent } from '~/common/socket/socket.js'; import { type VideoService } from '../videos/video.service.js'; import { REQUEST_DELAY } from './constants/constnats.js'; @@ -76,6 +78,7 @@ class AvatarVideoService { }) .then(() => { // TODO: NOTIFY USER + this.notifyAll(); }) .catch((error) => { throw new HttpError({ @@ -125,6 +128,13 @@ class AvatarVideoService { await this.azureAIService.removeAvatarVideo(id); } + + private notifyAll(): void { + const socket = socketEvent.getSocket(); + if (socket) { + socket.emit(AvatarVideoEvent.RENDER_SUCCESS); + } + } } export { AvatarVideoService }; diff --git a/backend/src/common/enums/avatar-video-event.enum.ts b/backend/src/common/enums/avatar-video-event.enum.ts new file mode 100644 index 000000000..4e52d447b --- /dev/null +++ b/backend/src/common/enums/avatar-video-event.enum.ts @@ -0,0 +1,5 @@ +const AvatarVideoEvent = { + RENDER_SUCCESS: 'render:complete', +} as const; + +export { AvatarVideoEvent }; diff --git a/backend/src/common/enums/enums.ts b/backend/src/common/enums/enums.ts index c5a3328bd..8101a1b03 100644 --- a/backend/src/common/enums/enums.ts +++ b/backend/src/common/enums/enums.ts @@ -1,2 +1,3 @@ +export { AvatarVideoEvent } from './avatar-video-event.enum.js'; export { parametersValidationMessage } from './parameters-validation-message.enum.js'; export { ApiPath, AppEnvironment, ServerErrorType } from 'shared'; diff --git a/backend/src/common/server-application/base-server-app.ts b/backend/src/common/server-application/base-server-app.ts index 57dc3eee9..d2cf4e8dc 100644 --- a/backend/src/common/server-application/base-server-app.ts +++ b/backend/src/common/server-application/base-server-app.ts @@ -11,6 +11,7 @@ import Fastify, { type FastifyReply, type FastifyRequest, } from 'fastify'; +import { type Socket, Server } from 'socket.io'; import { type Config } from '~/common/config/config.js'; import { type Database } from '~/common/database/database.js'; @@ -27,6 +28,7 @@ import { import { WHITE_ROUTES } from '../constants/constants.js'; import { authenticateJWT } from '../plugins/plugins.js'; +import { initSocketConnection } from './socket-application.js'; import { type ServerApp, type ServerAppApi, @@ -51,6 +53,8 @@ class BaseServerApp implements ServerApp { private app: ReturnType; + private io: Server; + public constructor({ config, logger, database, apis }: Constructor) { this.config = config; this.logger = logger; @@ -58,6 +62,12 @@ class BaseServerApp implements ServerApp { this.apis = apis; this.app = Fastify(); + this.io = new Server(this.app.server, { + cors: { + origin: '*', + methods: ['GET', 'POST'], + }, + }); } public addRoute(parameters: ServerAppRouteParameters): void { @@ -241,6 +251,10 @@ class BaseServerApp implements ServerApp { this.database.connect(); + this.io.on('connection', (socket: Socket) => + initSocketConnection(this.io, socket), + ); + await this.app .listen({ port: this.config.ENV.APP.PORT, diff --git a/backend/src/common/server-application/socket-application.ts b/backend/src/common/server-application/socket-application.ts new file mode 100644 index 000000000..4ee48b2f4 --- /dev/null +++ b/backend/src/common/server-application/socket-application.ts @@ -0,0 +1,11 @@ +import { type Server, type Socket } from 'socket.io'; + +import { socketEvent } from '../socket/socket.js'; + +const initSocketConnection = (io: Server, socket: Socket): void => { + socketEvent.initSocketConnection(io, socket); + + socket.on('disconnect', () => {}); +}; + +export { initSocketConnection }; diff --git a/backend/src/common/socket/scoket-event.ts b/backend/src/common/socket/scoket-event.ts new file mode 100644 index 000000000..ece39e3da --- /dev/null +++ b/backend/src/common/socket/scoket-event.ts @@ -0,0 +1,25 @@ +import EventTarget from 'node:events'; + +import { type Server, type Socket } from 'socket.io'; + +class SocketEvent extends EventTarget { + private io: Server | null = null; + private socket: Socket | null = null; + + public initSocketConnection(io: Server, socket: Socket): void { + this.io = io; + this.socket = socket; + } + + public getIo(): Server | null { + return this.io; + } + + public getSocket(): Socket | null { + return this.socket; + } +} + +const socketEvent = new SocketEvent(); + +export { socketEvent }; diff --git a/backend/src/common/socket/socket.ts b/backend/src/common/socket/socket.ts new file mode 100644 index 000000000..703956b43 --- /dev/null +++ b/backend/src/common/socket/socket.ts @@ -0,0 +1 @@ +export { socketEvent } from './scoket-event.js'; diff --git a/frontend/package.json b/frontend/package.json index 2fd069337..ada344810 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -52,6 +52,7 @@ "react-router-dom": "6.26.0", "remotion": "4.0.201", "shared": "*", + "socket.io-client": "4.7.5", "zod-formik-adapter": "1.3.0" } } diff --git a/frontend/src/bundles/common/context/socket.ts b/frontend/src/bundles/common/context/socket.ts new file mode 100644 index 000000000..af64976bf --- /dev/null +++ b/frontend/src/bundles/common/context/socket.ts @@ -0,0 +1,8 @@ +import React from 'react'; +import { type Socket } from 'socket.io-client'; +import { io } from 'socket.io-client'; + +const socket = io('http://localhost:3001'); +const SocketContext = React.createContext(socket); + +export { socket, SocketContext }; diff --git a/frontend/src/bundles/common/enums/avatar-video-event.enum.ts b/frontend/src/bundles/common/enums/avatar-video-event.enum.ts new file mode 100644 index 000000000..4e52d447b --- /dev/null +++ b/frontend/src/bundles/common/enums/avatar-video-event.enum.ts @@ -0,0 +1,5 @@ +const AvatarVideoEvent = { + RENDER_SUCCESS: 'render:complete', +} as const; + +export { AvatarVideoEvent }; diff --git a/frontend/src/bundles/common/enums/enums.ts b/frontend/src/bundles/common/enums/enums.ts index abc7ab32c..8b05f821a 100644 --- a/frontend/src/bundles/common/enums/enums.ts +++ b/frontend/src/bundles/common/enums/enums.ts @@ -1,4 +1,5 @@ export { AppRoute } from './app-route.enum.js'; +export { AvatarVideoEvent } from './avatar-video-event.enum.js'; export { DataStatus } from './data-status.enum.js'; export { VideoPreview } from './video-preview.enum.js'; export { diff --git a/frontend/src/bundles/common/hooks/hooks.ts b/frontend/src/bundles/common/hooks/hooks.ts index 75233c6dc..54afa076f 100644 --- a/frontend/src/bundles/common/hooks/hooks.ts +++ b/frontend/src/bundles/common/hooks/hooks.ts @@ -5,6 +5,7 @@ export { useAppSelector } from './use-app-selector/use-app-selector.hook.js'; export { useFormField } from './use-form-field/use-form-field.hook.js'; export { useCallback, + useContext, useEffect, useLayoutEffect, useMemo, diff --git a/frontend/src/bundles/home/components/main-content/main-content.tsx b/frontend/src/bundles/home/components/main-content/main-content.tsx index be7728d08..247d186a1 100644 --- a/frontend/src/bundles/home/components/main-content/main-content.tsx +++ b/frontend/src/bundles/home/components/main-content/main-content.tsx @@ -3,10 +3,12 @@ import { Loader, Overlay, } from '~/bundles/common/components/components.js'; -import { DataStatus } from '~/bundles/common/enums/enums.js'; +import { SocketContext } from '~/bundles/common/context/socket.js'; +import { AvatarVideoEvent, DataStatus } from '~/bundles/common/enums/enums.js'; import { useAppDispatch, useAppSelector, + useContext, useEffect, } from '~/bundles/common/hooks/hooks.js'; import { actions as homeActions } from '~/bundles/home/store/home.js'; @@ -15,6 +17,7 @@ import { VideoSection } from '../components.js'; const MainContent: React.FC = () => { const dispatch = useAppDispatch(); + const socket = useContext(SocketContext); const { videos, dataStatus } = useAppSelector(({ home }) => home); @@ -24,6 +27,18 @@ const MainContent: React.FC = () => { void dispatch(homeActions.loadUserVideos()); }, [dispatch]); + useEffect(() => { + // socket.on('TEST', (a: boolean) => { console.log('c: ' + a)} ); + // socket.emit(AvatarVideoEvent.RENDER_SUCCESS, true); + socket.on(AvatarVideoEvent.RENDER_SUCCESS, () => { + void dispatch(homeActions.loadUserVideos()); + }); + + return () => { + // socket.removeAllListeners(AvatarVideoEvent.RENDER_SUCCESS).close(); + }; + }, [socket, dispatch]); + return ( diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index efb013cc0..adf818968 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -9,12 +9,16 @@ import { import { store } from '~/framework/store/store.js'; import { routes } from '~/routes/routes.js'; +import { socket, SocketContext } from './bundles/common/context/socket.js'; + createRoot(document.querySelector('#root') as HTMLElement).render( - - - + + + + + , ); diff --git a/package-lock.json b/package-lock.json index 2dd29d8ef..d6cf49209 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,6 +65,7 @@ "pino": "9.3.2", "pino-pretty": "10.3.1", "shared": "*", + "socket.io": "4.7.5", "swagger-jsdoc": "6.2.8", "tiktoken": "1.0.16" }, @@ -105,6 +106,7 @@ "react-router-dom": "6.26.0", "remotion": "4.0.201", "shared": "*", + "socket.io-client": "4.7.5", "zod-formik-adapter": "1.3.0" }, "devDependencies": { @@ -6769,6 +6771,11 @@ "node": ">=16.0.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -6882,6 +6889,19 @@ "@types/node": "*" } }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", @@ -7454,6 +7474,18 @@ "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==" }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -8097,6 +8129,14 @@ } ] }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, "node_modules/bcrypt": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz", @@ -8856,6 +8896,18 @@ "url": "https://opencollective.com/core-js" } }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", @@ -9483,6 +9535,94 @@ "once": "^1.4.0" } }, + "node_modules/engine.io": { + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", + "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz", + "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -13561,6 +13701,14 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-abi": { "version": "3.67.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", @@ -15918,6 +16066,78 @@ "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", "dev": true }, + "node_modules/socket.io": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", + "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.2", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sonic-boom": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", @@ -17636,6 +17856,14 @@ "node": ">= 0.10" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/vite": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz", @@ -18771,6 +18999,14 @@ "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==", "dev": true }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", From 8ecce998023f2fc7c384ff54aad2d5ad7160ca52 Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Mon, 16 Sep 2024 15:57:39 -0400 Subject: [PATCH 02/18] OV-275: * use of enum and objects for better strcutue, add notifications, use only one useEffect --- .../avatar-videos/avatar-videos.service.ts | 9 ++-- .../common/enums/avatar-video-event.enum.ts | 3 +- backend/src/common/enums/enums.ts | 1 + backend/src/common/enums/socket-event.enum.ts | 6 +++ .../server-application/base-server-app.ts | 10 ++--- .../server-application/socket-application.ts | 3 +- frontend/src/bundles/common/context/socket.ts | 4 +- .../common/enums/avatar-video-event.enum.ts | 3 +- .../components/main-content/main-content.tsx | 45 ++++++++++++++----- .../src/bundles/home/constants/constants.ts | 2 + ...-render-failed-notification-id.constant.ts | 3 ++ ...render-success-notification-id.constant.ts | 3 ++ frontend/src/bundles/home/enums/enums.ts | 2 + .../home/enums/notification-message.enum.ts | 6 +++ .../home/enums/notification-title.enum.ts | 6 +++ 15 files changed, 81 insertions(+), 25 deletions(-) create mode 100644 backend/src/common/enums/socket-event.enum.ts create mode 100644 frontend/src/bundles/home/constants/constants.ts create mode 100644 frontend/src/bundles/home/constants/video-render-failed-notification-id.constant.ts create mode 100644 frontend/src/bundles/home/constants/video-render-success-notification-id.constant.ts create mode 100644 frontend/src/bundles/home/enums/notification-message.enum.ts create mode 100644 frontend/src/bundles/home/enums/notification-title.enum.ts diff --git a/backend/src/bundles/avatar-videos/avatar-videos.service.ts b/backend/src/bundles/avatar-videos/avatar-videos.service.ts index e4ada65a5..5e9f8081a 100644 --- a/backend/src/bundles/avatar-videos/avatar-videos.service.ts +++ b/backend/src/bundles/avatar-videos/avatar-videos.service.ts @@ -77,8 +77,7 @@ class AvatarVideoService { url: response.outputs.result, }) .then(() => { - // TODO: NOTIFY USER - this.notifyAll(); + this.emitNotification(AvatarVideoEvent.RENDER_SUCCESS); }) .catch((error) => { throw new HttpError({ @@ -92,7 +91,7 @@ class AvatarVideoService { } else if ( response.status === GenerateAvatarResponseStatus.FAILED ) { - // TODO: NOTIFY USER + this.emitNotification(AvatarVideoEvent.RENDER_FAILED); clearInterval(interval); } }) @@ -129,10 +128,10 @@ class AvatarVideoService { await this.azureAIService.removeAvatarVideo(id); } - private notifyAll(): void { + private emitNotification(event: string): void { const socket = socketEvent.getSocket(); if (socket) { - socket.emit(AvatarVideoEvent.RENDER_SUCCESS); + socket.emit(event); } } } diff --git a/backend/src/common/enums/avatar-video-event.enum.ts b/backend/src/common/enums/avatar-video-event.enum.ts index 4e52d447b..4e8bae4ba 100644 --- a/backend/src/common/enums/avatar-video-event.enum.ts +++ b/backend/src/common/enums/avatar-video-event.enum.ts @@ -1,5 +1,6 @@ const AvatarVideoEvent = { - RENDER_SUCCESS: 'render:complete', + RENDER_SUCCESS: 'render:success', + RENDER_FAILED: 'render:failed', } as const; export { AvatarVideoEvent }; diff --git a/backend/src/common/enums/enums.ts b/backend/src/common/enums/enums.ts index 8101a1b03..b692e443f 100644 --- a/backend/src/common/enums/enums.ts +++ b/backend/src/common/enums/enums.ts @@ -1,3 +1,4 @@ export { AvatarVideoEvent } from './avatar-video-event.enum.js'; export { parametersValidationMessage } from './parameters-validation-message.enum.js'; +export { SocketEvent } from './socket-event.enum.js'; export { ApiPath, AppEnvironment, ServerErrorType } from 'shared'; diff --git a/backend/src/common/enums/socket-event.enum.ts b/backend/src/common/enums/socket-event.enum.ts new file mode 100644 index 000000000..052bba5fa --- /dev/null +++ b/backend/src/common/enums/socket-event.enum.ts @@ -0,0 +1,6 @@ +const SocketEvent = { + CONNECTION: 'connection', + DISCONNECT: 'disconnect', +} as const; + +export { SocketEvent }; diff --git a/backend/src/common/server-application/base-server-app.ts b/backend/src/common/server-application/base-server-app.ts index d2cf4e8dc..07cec6383 100644 --- a/backend/src/common/server-application/base-server-app.ts +++ b/backend/src/common/server-application/base-server-app.ts @@ -15,9 +15,9 @@ import { type Socket, Server } from 'socket.io'; import { type Config } from '~/common/config/config.js'; import { type Database } from '~/common/database/database.js'; -import { ServerErrorType } from '~/common/enums/enums.js'; +import { ServerErrorType, SocketEvent } from '~/common/enums/enums.js'; import { type ValidationError } from '~/common/exceptions/exceptions.js'; -import { HttpCode, HttpError } from '~/common/http/http.js'; +import { HttpCode, HttpError, HTTPMethod } from '~/common/http/http.js'; import { type Logger } from '~/common/logger/logger.js'; import { session } from '~/common/plugins/session/session.plugin.js'; import { @@ -64,8 +64,8 @@ class BaseServerApp implements ServerApp { this.app = Fastify(); this.io = new Server(this.app.server, { cors: { - origin: '*', - methods: ['GET', 'POST'], + origin: this.config.ENV.APP.ORIGIN, + methods: [HTTPMethod.GET, HTTPMethod.POST], }, }); } @@ -251,7 +251,7 @@ class BaseServerApp implements ServerApp { this.database.connect(); - this.io.on('connection', (socket: Socket) => + this.io.on(SocketEvent.CONNECTION, (socket: Socket) => initSocketConnection(this.io, socket), ); diff --git a/backend/src/common/server-application/socket-application.ts b/backend/src/common/server-application/socket-application.ts index 4ee48b2f4..09c00ccfa 100644 --- a/backend/src/common/server-application/socket-application.ts +++ b/backend/src/common/server-application/socket-application.ts @@ -1,11 +1,12 @@ import { type Server, type Socket } from 'socket.io'; +import { SocketEvent } from '../enums/enums.js'; import { socketEvent } from '../socket/socket.js'; const initSocketConnection = (io: Server, socket: Socket): void => { socketEvent.initSocketConnection(io, socket); - socket.on('disconnect', () => {}); + socket.on(SocketEvent.DISCONNECT, () => {}); }; export { initSocketConnection }; diff --git a/frontend/src/bundles/common/context/socket.ts b/frontend/src/bundles/common/context/socket.ts index af64976bf..d1212f8e9 100644 --- a/frontend/src/bundles/common/context/socket.ts +++ b/frontend/src/bundles/common/context/socket.ts @@ -2,7 +2,9 @@ import React from 'react'; import { type Socket } from 'socket.io-client'; import { io } from 'socket.io-client'; -const socket = io('http://localhost:3001'); +const serverUrl = import.meta.env['VITE_APP_PROXY_SERVER_URL']; + +const socket = io(serverUrl); const SocketContext = React.createContext(socket); export { socket, SocketContext }; diff --git a/frontend/src/bundles/common/enums/avatar-video-event.enum.ts b/frontend/src/bundles/common/enums/avatar-video-event.enum.ts index 4e52d447b..4e8bae4ba 100644 --- a/frontend/src/bundles/common/enums/avatar-video-event.enum.ts +++ b/frontend/src/bundles/common/enums/avatar-video-event.enum.ts @@ -1,5 +1,6 @@ const AvatarVideoEvent = { - RENDER_SUCCESS: 'render:complete', + RENDER_SUCCESS: 'render:success', + RENDER_FAILED: 'render:failed', } as const; export { AvatarVideoEvent }; diff --git a/frontend/src/bundles/home/components/main-content/main-content.tsx b/frontend/src/bundles/home/components/main-content/main-content.tsx index 247d186a1..8c78bd2fb 100644 --- a/frontend/src/bundles/home/components/main-content/main-content.tsx +++ b/frontend/src/bundles/home/components/main-content/main-content.tsx @@ -11,8 +11,14 @@ import { useContext, useEffect, } from '~/bundles/common/hooks/hooks.js'; +import { notificationService } from '~/bundles/common/services/services.js'; import { actions as homeActions } from '~/bundles/home/store/home.js'; +import { + VIDEO_RENDER_FAILED_NOTIFICATION_ID, + VIDEO_RENDER_SUCCESS_NOTIFICATION_ID, +} from '../../constants/constants.js'; +import { NotificationMessage, NotificationTitle } from '../../enums/enums.js'; import { VideoSection } from '../components.js'; const MainContent: React.FC = () => { @@ -22,22 +28,39 @@ const MainContent: React.FC = () => { const { videos, dataStatus } = useAppSelector(({ home }) => home); // TODO: filter videos to get recent videos - useEffect(() => { - void dispatch(homeActions.loadUserVideos()); - }, [dispatch]); - - useEffect(() => { - // socket.on('TEST', (a: boolean) => { console.log('c: ' + a)} ); - // socket.emit(AvatarVideoEvent.RENDER_SUCCESS, true); - socket.on(AvatarVideoEvent.RENDER_SUCCESS, () => { + const loadUserVideos = (): void => { void dispatch(homeActions.loadUserVideos()); - }); + }; + + const renderedVideoSuccess = (): void => { + notificationService.success({ + id: VIDEO_RENDER_SUCCESS_NOTIFICATION_ID, + title: NotificationTitle.VIDEO_RENDER_SUCCESS, + message: NotificationMessage.VIDEO_RENDER_SUCCESS, + }); + loadUserVideos(); + }; + + const renderedVideoFailed = (): void => { + socket.on(AvatarVideoEvent.RENDER_FAILED, () => { + notificationService.error({ + id: VIDEO_RENDER_FAILED_NOTIFICATION_ID, + title: NotificationTitle.VIDEO_RENDER_FAILED, + message: NotificationMessage.VIDEO_RENDER_FAILED, + }); + }); + }; + + loadUserVideos(); + socket.on(AvatarVideoEvent.RENDER_SUCCESS, renderedVideoSuccess); + socket.on(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); return () => { - // socket.removeAllListeners(AvatarVideoEvent.RENDER_SUCCESS).close(); + socket.off(AvatarVideoEvent.RENDER_FAILED, renderedVideoSuccess); + socket.off(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); }; - }, [socket, dispatch]); + }, [dispatch, socket]); return ( diff --git a/frontend/src/bundles/home/constants/constants.ts b/frontend/src/bundles/home/constants/constants.ts new file mode 100644 index 000000000..45a5959eb --- /dev/null +++ b/frontend/src/bundles/home/constants/constants.ts @@ -0,0 +1,2 @@ +export { VIDEO_RENDER_FAILED_NOTIFICATION_ID } from './video-render-failed-notification-id.constant.js'; +export { VIDEO_RENDER_SUCCESS_NOTIFICATION_ID } from './video-render-success-notification-id.constant.js'; diff --git a/frontend/src/bundles/home/constants/video-render-failed-notification-id.constant.ts b/frontend/src/bundles/home/constants/video-render-failed-notification-id.constant.ts new file mode 100644 index 000000000..78d2fc561 --- /dev/null +++ b/frontend/src/bundles/home/constants/video-render-failed-notification-id.constant.ts @@ -0,0 +1,3 @@ +const VIDEO_RENDER_FAILED_NOTIFICATION_ID = 'video-render-failed'; + +export { VIDEO_RENDER_FAILED_NOTIFICATION_ID }; diff --git a/frontend/src/bundles/home/constants/video-render-success-notification-id.constant.ts b/frontend/src/bundles/home/constants/video-render-success-notification-id.constant.ts new file mode 100644 index 000000000..8521e16d0 --- /dev/null +++ b/frontend/src/bundles/home/constants/video-render-success-notification-id.constant.ts @@ -0,0 +1,3 @@ +const VIDEO_RENDER_SUCCESS_NOTIFICATION_ID = 'video-render-success'; + +export { VIDEO_RENDER_SUCCESS_NOTIFICATION_ID }; diff --git a/frontend/src/bundles/home/enums/enums.ts b/frontend/src/bundles/home/enums/enums.ts index 7e0da47c3..924a10d91 100644 --- a/frontend/src/bundles/home/enums/enums.ts +++ b/frontend/src/bundles/home/enums/enums.ts @@ -1 +1,3 @@ +export { NotificationMessage } from './notification-message.enum.js'; +export { NotificationTitle } from './notification-title.enum.js'; export { VideosApiPath } from 'shared'; diff --git a/frontend/src/bundles/home/enums/notification-message.enum.ts b/frontend/src/bundles/home/enums/notification-message.enum.ts new file mode 100644 index 000000000..ffcb775dd --- /dev/null +++ b/frontend/src/bundles/home/enums/notification-message.enum.ts @@ -0,0 +1,6 @@ +const NotificationMessage = { + VIDEO_RENDER_SUCCESS: 'Video rendered successfully', + VIDEO_RENDER_FAILED: 'Video render failed', +} as const; + +export { NotificationMessage }; diff --git a/frontend/src/bundles/home/enums/notification-title.enum.ts b/frontend/src/bundles/home/enums/notification-title.enum.ts new file mode 100644 index 000000000..18dcb0fcd --- /dev/null +++ b/frontend/src/bundles/home/enums/notification-title.enum.ts @@ -0,0 +1,6 @@ +const NotificationTitle = { + VIDEO_RENDER_SUCCESS: 'Video rendered', + VIDEO_RENDER_FAILED: 'Video render failed', +} as const; + +export { NotificationTitle }; From c4547b882850c7fde14c5e7e4029ff06bf4ab77f Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Mon, 16 Sep 2024 17:50:17 -0400 Subject: [PATCH 03/18] OV-275: * use of prettier, correct Cleanup --- backend/src/bundles/avatar-videos/avatar-videos.service.ts | 4 +++- frontend/src/bundles/common/context/socket.ts | 3 +-- .../src/bundles/home/components/main-content/main-content.tsx | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/backend/src/bundles/avatar-videos/avatar-videos.service.ts b/backend/src/bundles/avatar-videos/avatar-videos.service.ts index 5e9f8081a..6a6845017 100644 --- a/backend/src/bundles/avatar-videos/avatar-videos.service.ts +++ b/backend/src/bundles/avatar-videos/avatar-videos.service.ts @@ -77,7 +77,9 @@ class AvatarVideoService { url: response.outputs.result, }) .then(() => { - this.emitNotification(AvatarVideoEvent.RENDER_SUCCESS); + this.emitNotification( + AvatarVideoEvent.RENDER_SUCCESS, + ); }) .catch((error) => { throw new HttpError({ diff --git a/frontend/src/bundles/common/context/socket.ts b/frontend/src/bundles/common/context/socket.ts index d1212f8e9..fbe504396 100644 --- a/frontend/src/bundles/common/context/socket.ts +++ b/frontend/src/bundles/common/context/socket.ts @@ -1,6 +1,5 @@ import React from 'react'; -import { type Socket } from 'socket.io-client'; -import { io } from 'socket.io-client'; +import { type Socket,io } from 'socket.io-client'; const serverUrl = import.meta.env['VITE_APP_PROXY_SERVER_URL']; diff --git a/frontend/src/bundles/home/components/main-content/main-content.tsx b/frontend/src/bundles/home/components/main-content/main-content.tsx index 4903268be..86c8c3a32 100644 --- a/frontend/src/bundles/home/components/main-content/main-content.tsx +++ b/frontend/src/bundles/home/components/main-content/main-content.tsx @@ -58,7 +58,7 @@ const MainContent: React.FC = () => { socket.on(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); return () => { - socket.off(AvatarVideoEvent.RENDER_FAILED, renderedVideoSuccess); + socket.off(AvatarVideoEvent.RENDER_SUCCESS, renderedVideoSuccess); socket.off(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); }; }, [dispatch, socket]); From b4a373da69d232fc320191870f0c2fca9390c28b Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Mon, 16 Sep 2024 19:21:00 -0400 Subject: [PATCH 04/18] OV-275: * use of on mehtod to emit notification, ensure that websoctes are used --- .../bundles/avatar-videos/avatar-videos.service.ts | 13 ++++--------- backend/src/common/constants/constants.ts | 1 + .../common/constants/socket-trasnport.constants.ts | 3 +++ .../common/server-application/base-server-app.ts | 9 +++++++-- backend/src/common/socket/scoket-event.ts | 6 ++++++ frontend/src/bundles/common/constants/constants.ts | 1 + .../common/constants/socket-trasnport.constants.ts | 3 +++ frontend/src/bundles/common/context/socket.ts | 9 +++++++-- 8 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 backend/src/common/constants/socket-trasnport.constants.ts create mode 100644 frontend/src/bundles/common/constants/socket-trasnport.constants.ts diff --git a/backend/src/bundles/avatar-videos/avatar-videos.service.ts b/backend/src/bundles/avatar-videos/avatar-videos.service.ts index 6a6845017..505873886 100644 --- a/backend/src/bundles/avatar-videos/avatar-videos.service.ts +++ b/backend/src/bundles/avatar-videos/avatar-videos.service.ts @@ -77,7 +77,7 @@ class AvatarVideoService { url: response.outputs.result, }) .then(() => { - this.emitNotification( + socketEvent.emitNotification( AvatarVideoEvent.RENDER_SUCCESS, ); }) @@ -93,7 +93,9 @@ class AvatarVideoService { } else if ( response.status === GenerateAvatarResponseStatus.FAILED ) { - this.emitNotification(AvatarVideoEvent.RENDER_FAILED); + socketEvent.emitNotification( + AvatarVideoEvent.RENDER_FAILED, + ); clearInterval(interval); } }) @@ -129,13 +131,6 @@ class AvatarVideoService { await this.azureAIService.removeAvatarVideo(id); } - - private emitNotification(event: string): void { - const socket = socketEvent.getSocket(); - if (socket) { - socket.emit(event); - } - } } export { AvatarVideoService }; diff --git a/backend/src/common/constants/constants.ts b/backend/src/common/constants/constants.ts index 1a5d15784..a707f62d8 100644 --- a/backend/src/common/constants/constants.ts +++ b/backend/src/common/constants/constants.ts @@ -1,2 +1,3 @@ +export { SOCKET_TRANSPORT_WEBSOCKETS } from './socket-trasnport.constants.js'; export { USER_PASSWORD_SALT_ROUNDS } from './user.constants.js'; export { WHITE_ROUTES } from './white-routes.constants.js'; diff --git a/backend/src/common/constants/socket-trasnport.constants.ts b/backend/src/common/constants/socket-trasnport.constants.ts new file mode 100644 index 000000000..4bc632c5d --- /dev/null +++ b/backend/src/common/constants/socket-trasnport.constants.ts @@ -0,0 +1,3 @@ +const SOCKET_TRANSPORT_WEBSOCKETS = 'websocket'; + +export { SOCKET_TRANSPORT_WEBSOCKETS }; diff --git a/backend/src/common/server-application/base-server-app.ts b/backend/src/common/server-application/base-server-app.ts index 07cec6383..dbca207ba 100644 --- a/backend/src/common/server-application/base-server-app.ts +++ b/backend/src/common/server-application/base-server-app.ts @@ -14,11 +14,16 @@ import Fastify, { import { type Socket, Server } from 'socket.io'; import { type Config } from '~/common/config/config.js'; +import { + SOCKET_TRANSPORT_WEBSOCKETS, + WHITE_ROUTES, +} from '~/common/constants/constants.js'; import { type Database } from '~/common/database/database.js'; import { ServerErrorType, SocketEvent } from '~/common/enums/enums.js'; import { type ValidationError } from '~/common/exceptions/exceptions.js'; import { HttpCode, HttpError, HTTPMethod } from '~/common/http/http.js'; import { type Logger } from '~/common/logger/logger.js'; +import { authenticateJWT } from '~/common/plugins/plugins.js'; import { session } from '~/common/plugins/session/session.plugin.js'; import { type ServerCommonErrorResponse, @@ -26,8 +31,6 @@ import { type ValidationSchema, } from '~/common/types/types.js'; -import { WHITE_ROUTES } from '../constants/constants.js'; -import { authenticateJWT } from '../plugins/plugins.js'; import { initSocketConnection } from './socket-application.js'; import { type ServerApp, @@ -63,6 +66,8 @@ class BaseServerApp implements ServerApp { this.app = Fastify(); this.io = new Server(this.app.server, { + // This is to ensure that it dosent fall back to long polling as it return a 404 if it does + transports: [SOCKET_TRANSPORT_WEBSOCKETS], cors: { origin: this.config.ENV.APP.ORIGIN, methods: [HTTPMethod.GET, HTTPMethod.POST], diff --git a/backend/src/common/socket/scoket-event.ts b/backend/src/common/socket/scoket-event.ts index ece39e3da..424e85774 100644 --- a/backend/src/common/socket/scoket-event.ts +++ b/backend/src/common/socket/scoket-event.ts @@ -18,6 +18,12 @@ class SocketEvent extends EventTarget { public getSocket(): Socket | null { return this.socket; } + + public emitNotification(event: string): void { + if (this.socket) { + this.socket.emit(event); + } + } } const socketEvent = new SocketEvent(); diff --git a/frontend/src/bundles/common/constants/constants.ts b/frontend/src/bundles/common/constants/constants.ts index 508843d12..b6e47aaf7 100644 --- a/frontend/src/bundles/common/constants/constants.ts +++ b/frontend/src/bundles/common/constants/constants.ts @@ -1 +1,2 @@ export { FPS } from './fps.constant.js'; +export { SOCKET_TRANSPORT_WEBSOCKETS } from './socket-trasnport.constants.js'; diff --git a/frontend/src/bundles/common/constants/socket-trasnport.constants.ts b/frontend/src/bundles/common/constants/socket-trasnport.constants.ts new file mode 100644 index 000000000..4bc632c5d --- /dev/null +++ b/frontend/src/bundles/common/constants/socket-trasnport.constants.ts @@ -0,0 +1,3 @@ +const SOCKET_TRANSPORT_WEBSOCKETS = 'websocket'; + +export { SOCKET_TRANSPORT_WEBSOCKETS }; diff --git a/frontend/src/bundles/common/context/socket.ts b/frontend/src/bundles/common/context/socket.ts index fbe504396..2f082acf8 100644 --- a/frontend/src/bundles/common/context/socket.ts +++ b/frontend/src/bundles/common/context/socket.ts @@ -1,9 +1,14 @@ import React from 'react'; -import { type Socket,io } from 'socket.io-client'; +import { type Socket, io } from 'socket.io-client'; + +import { SOCKET_TRANSPORT_WEBSOCKETS } from '~/bundles/common/constants/constants.js'; const serverUrl = import.meta.env['VITE_APP_PROXY_SERVER_URL']; -const socket = io(serverUrl); +const socket = io(serverUrl, { + // This is to ensure that it dosent fall back to long polling as it return a 404 if it does + transports: [SOCKET_TRANSPORT_WEBSOCKETS], +}); const SocketContext = React.createContext(socket); export { socket, SocketContext }; From a15ff7e2f97b733263f8e4fe660b15d0f49f89e7 Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Tue, 17 Sep 2024 18:30:04 -0400 Subject: [PATCH 05/18] OV-275: * use prettier --- backend/src/bundles/avatar-videos/avatar-videos.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/bundles/avatar-videos/avatar-videos.service.ts b/backend/src/bundles/avatar-videos/avatar-videos.service.ts index 520afb1a9..dedb6aa11 100644 --- a/backend/src/bundles/avatar-videos/avatar-videos.service.ts +++ b/backend/src/bundles/avatar-videos/avatar-videos.service.ts @@ -195,9 +195,7 @@ class AvatarVideoService { }); } - socketEvent.emitNotification( - AvatarVideoEvent.RENDER_SUCCESS, - ); + socketEvent.emitNotification(AvatarVideoEvent.RENDER_SUCCESS); await Promise.all( avatars.map((avatar) => { From 1dedc8a70c69e1ee034960c90e6d4b1cd150c8b3 Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Wed, 18 Sep 2024 19:00:34 -0400 Subject: [PATCH 06/18] OV-275: * change function name to start with "handle" --- .../components/main-content/main-content.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/frontend/src/bundles/home/components/main-content/main-content.tsx b/frontend/src/bundles/home/components/main-content/main-content.tsx index 86c8c3a32..7d4a99ecd 100644 --- a/frontend/src/bundles/home/components/main-content/main-content.tsx +++ b/frontend/src/bundles/home/components/main-content/main-content.tsx @@ -30,20 +30,20 @@ const MainContent: React.FC = () => { // TODO: filter videos to get recent videos useEffect(() => { - const loadUserVideos = (): void => { + const handleLoadUserVideos = (): void => { void dispatch(homeActions.loadUserVideos()); }; - const renderedVideoSuccess = (): void => { + const handleRenderedVideoSuccess = (): void => { notificationService.success({ id: VIDEO_RENDER_SUCCESS_NOTIFICATION_ID, title: NotificationTitle.VIDEO_RENDER_SUCCESS, message: NotificationMessage.VIDEO_RENDER_SUCCESS, }); - loadUserVideos(); + handleLoadUserVideos(); }; - const renderedVideoFailed = (): void => { + const handleRenderedVideoFailed = (): void => { socket.on(AvatarVideoEvent.RENDER_FAILED, () => { notificationService.error({ id: VIDEO_RENDER_FAILED_NOTIFICATION_ID, @@ -53,13 +53,13 @@ const MainContent: React.FC = () => { }); }; - loadUserVideos(); - socket.on(AvatarVideoEvent.RENDER_SUCCESS, renderedVideoSuccess); - socket.on(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); + handleLoadUserVideos(); + socket.on(AvatarVideoEvent.RENDER_SUCCESS, handleRenderedVideoSuccess); + socket.on(AvatarVideoEvent.RENDER_FAILED, handleRenderedVideoFailed); return () => { - socket.off(AvatarVideoEvent.RENDER_SUCCESS, renderedVideoSuccess); - socket.off(AvatarVideoEvent.RENDER_FAILED, renderedVideoFailed); + socket.off(AvatarVideoEvent.RENDER_SUCCESS, handleRenderedVideoSuccess); + socket.off(AvatarVideoEvent.RENDER_FAILED, handleRenderedVideoFailed); }; }, [dispatch, socket]); From e842fb8d2d676a4646ba204516c1879c9f137cd6 Mon Sep 17 00:00:00 2001 From: Luis Felix Date: Wed, 18 Sep 2024 19:05:43 -0400 Subject: [PATCH 07/18] OV-275: * use of prettier --- .../home/components/main-content/main-content.tsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/home/components/main-content/main-content.tsx b/frontend/src/bundles/home/components/main-content/main-content.tsx index 7d4a99ecd..0a9f0f523 100644 --- a/frontend/src/bundles/home/components/main-content/main-content.tsx +++ b/frontend/src/bundles/home/components/main-content/main-content.tsx @@ -58,8 +58,14 @@ const MainContent: React.FC = () => { socket.on(AvatarVideoEvent.RENDER_FAILED, handleRenderedVideoFailed); return () => { - socket.off(AvatarVideoEvent.RENDER_SUCCESS, handleRenderedVideoSuccess); - socket.off(AvatarVideoEvent.RENDER_FAILED, handleRenderedVideoFailed); + socket.off( + AvatarVideoEvent.RENDER_SUCCESS, + handleRenderedVideoSuccess, + ); + socket.off( + AvatarVideoEvent.RENDER_FAILED, + handleRenderedVideoFailed, + ); }; }, [dispatch, socket]); From ddaff63d0948ca3fff6bb044e4ab9600c8c9dd3a Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Mon, 23 Sep 2024 18:38:43 +0200 Subject: [PATCH 08/18] OV-393: * remove listeners for plus button --- frontend/src/bundles/studio/components/timeline/item/item.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/studio/components/timeline/item/item.tsx b/frontend/src/bundles/studio/components/timeline/item/item.tsx index ad83a15ed..d70161458 100644 --- a/frontend/src/bundles/studio/components/timeline/item/item.tsx +++ b/frontend/src/bundles/studio/components/timeline/item/item.tsx @@ -2,6 +2,7 @@ import { type Span } from 'dnd-timeline'; import { Box, Flex } from '~/bundles/common/components/components.js'; import { useAppSelector } from '~/bundles/common/hooks/hooks.js'; +import { RowNames } from '~/bundles/studio/enums/enums.js'; import { useTimelineItem } from '~/bundles/studio/hooks/hooks.js'; import { type RowType } from '~/bundles/studio/types/types.js'; @@ -34,7 +35,7 @@ const Item: React.FC = ({ id, type, span, children, onClick }) => { return ( Date: Tue, 24 Sep 2024 16:10:18 +0300 Subject: [PATCH 09/18] OV-401: * fix script scroll --- .../menu-content/script-content/components/script.tsx | 4 ++++ .../menu-content/script-content/components/styles.module.css | 3 +++ 2 files changed, 7 insertions(+) create mode 100644 frontend/src/bundles/studio/components/video-menu/components/menu-content/script-content/components/styles.module.css diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/script-content/components/script.tsx b/frontend/src/bundles/studio/components/video-menu/components/menu-content/script-content/components/script.tsx index 27a68719a..95e536bf2 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/script-content/components/script.tsx +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/script-content/components/script.tsx @@ -22,6 +22,8 @@ import { PlayIconNames } from '~/bundles/studio/enums/play-icon-names.enum.js'; import { actions as studioActions } from '~/bundles/studio/store/studio.js'; import { type ScriptWithIcon as ScriptT } from '~/bundles/studio/types/types.js'; +import styles from './styles.module.css'; + type Properties = ScriptT & { handleChangeVoice: (scriptId: string) => void }; const Script: React.FC = ({ @@ -141,6 +143,7 @@ const Script: React.FC = ({ w="full" > = ({ borderColor="background.600" /> Date: Tue, 24 Sep 2024 16:06:18 +0200 Subject: [PATCH 10/18] OV-410: * when resizing scene - remove plus button --- .../studio/components/timeline/item/item.tsx | 14 +++++- .../components/timeline/rows/scenes-row.tsx | 46 ++++++++++++------- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/frontend/src/bundles/studio/components/timeline/item/item.tsx b/frontend/src/bundles/studio/components/timeline/item/item.tsx index ad83a15ed..01829a1a1 100644 --- a/frontend/src/bundles/studio/components/timeline/item/item.tsx +++ b/frontend/src/bundles/studio/components/timeline/item/item.tsx @@ -13,9 +13,19 @@ type Properties = { span: Span; children: React.ReactNode; onClick?: React.MouseEventHandler; + onResizeStart?: () => void; + onResizeEnd?: () => void; }; -const Item: React.FC = ({ id, type, span, children, onClick }) => { +const Item: React.FC = ({ + id, + type, + span, + children, + onClick, + onResizeStart = (): void => {}, + onResizeEnd = (): void => {}, +}) => { const selectedItem = useAppSelector(({ studio }) => studio.ui.selectedItem); const { @@ -29,6 +39,8 @@ const Item: React.FC = ({ id, type, span, children, onClick }) => { id, span, data: { type }, + onResizeEnd, + onResizeStart, }); return ( diff --git a/frontend/src/bundles/studio/components/timeline/rows/scenes-row.tsx b/frontend/src/bundles/studio/components/timeline/rows/scenes-row.tsx index f8d429603..75a899080 100644 --- a/frontend/src/bundles/studio/components/timeline/rows/scenes-row.tsx +++ b/frontend/src/bundles/studio/components/timeline/rows/scenes-row.tsx @@ -8,6 +8,7 @@ import { useAppSelector, useCallback, useMemo, + useState, } from '~/bundles/common/hooks/hooks.js'; import { IconName, IconSize } from '~/bundles/common/icons/icons.js'; import { Control } from '~/bundles/studio/components/components.js'; @@ -23,6 +24,7 @@ import { Item, Row } from '../components.js'; import styles from './styles.module.css'; const ScenesRow: React.FC = () => { + const [isResizing, setIsResizing] = useState(false); const scenes = useAppSelector(({ studio }) => studio.scenes); const scenesWithSpan = useMemo(() => setItemsSpan(scenes), [scenes]); const { pixelsToValue } = useTimelineContext(); @@ -70,6 +72,14 @@ const ScenesRow: React.FC = () => { [dispatch], ); + const handleResizing = useCallback((): void => { + setIsResizing(true); + }, []); + + const handleResizingEnd = useCallback((): void => { + setIsResizing(false); + }, []); + return ( { type={RowNames.SCENE} {...item} onClick={handleItemClick} + onResizeEnd={handleResizingEnd} + onResizeStart={handleResizing} > { ))} - - - + {!isResizing && ( + + + + )} ); }; From 74834cbc69195172478f08c6225e7ed5aa445eb1 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 17:16:39 +0200 Subject: [PATCH 11/18] OV-415: * rename some constants and create min duration scene --- .../studio/constants/default-scene-duration.constant.ts | 3 +++ .../studio/constants/default-script-duration.constant.ts | 3 +++ .../bundles/studio/constants/min-scene-duration.constant.ts | 2 +- .../bundles/studio/constants/min-script-duration.constant.ts | 3 --- 4 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 frontend/src/bundles/studio/constants/default-scene-duration.constant.ts create mode 100644 frontend/src/bundles/studio/constants/default-script-duration.constant.ts delete mode 100644 frontend/src/bundles/studio/constants/min-script-duration.constant.ts diff --git a/frontend/src/bundles/studio/constants/default-scene-duration.constant.ts b/frontend/src/bundles/studio/constants/default-scene-duration.constant.ts new file mode 100644 index 000000000..48651ce1f --- /dev/null +++ b/frontend/src/bundles/studio/constants/default-scene-duration.constant.ts @@ -0,0 +1,3 @@ +const DEFAULT_SCENE_DURATION = 15; + +export { DEFAULT_SCENE_DURATION }; diff --git a/frontend/src/bundles/studio/constants/default-script-duration.constant.ts b/frontend/src/bundles/studio/constants/default-script-duration.constant.ts new file mode 100644 index 000000000..d0e44efe3 --- /dev/null +++ b/frontend/src/bundles/studio/constants/default-script-duration.constant.ts @@ -0,0 +1,3 @@ +const DEFAULT_SCRIPT_DURATION = 10; + +export { DEFAULT_SCRIPT_DURATION }; diff --git a/frontend/src/bundles/studio/constants/min-scene-duration.constant.ts b/frontend/src/bundles/studio/constants/min-scene-duration.constant.ts index 0f49a6f8a..0d38b1fb9 100644 --- a/frontend/src/bundles/studio/constants/min-scene-duration.constant.ts +++ b/frontend/src/bundles/studio/constants/min-scene-duration.constant.ts @@ -1,3 +1,3 @@ -const MIN_SCENE_DURATION = 15; +const MIN_SCENE_DURATION = 1; export { MIN_SCENE_DURATION }; diff --git a/frontend/src/bundles/studio/constants/min-script-duration.constant.ts b/frontend/src/bundles/studio/constants/min-script-duration.constant.ts deleted file mode 100644 index 535760003..000000000 --- a/frontend/src/bundles/studio/constants/min-script-duration.constant.ts +++ /dev/null @@ -1,3 +0,0 @@ -const MIN_SCRIPT_DURATION = 10; - -export { MIN_SCRIPT_DURATION }; From df6e6354a76105f176c0bced44e37ce1a6820597 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 17:23:39 +0200 Subject: [PATCH 12/18] OV-415: * constants --- frontend/src/bundles/studio/constants/constants.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/studio/constants/constants.ts b/frontend/src/bundles/studio/constants/constants.ts index 87a4728dc..31bc043be 100644 --- a/frontend/src/bundles/studio/constants/constants.ts +++ b/frontend/src/bundles/studio/constants/constants.ts @@ -1,11 +1,12 @@ export { ADD_BUTTON_PADDING_MILLISECONDS } from './add-button-padding-milliseconds.js'; +export { DEFAULT_SCENE_DURATION } from './default-scene-duration.constant.js'; +export { DEFAULT_SCRIPT_DURATION } from './default-script-duration.constant.js'; export { DEFAULT_VIDEO_NAME } from './default-video-name.js'; export { DEFAULT_VOICE } from './default-voice-name.constant.js'; export { DND_ACTIVATION_DISTANCE_PIXELS } from './dnd-activation-distance-pixels.constant.js'; export { GROW_COEFFICIENT } from './grow-coefficient.js'; export { MAX_SCENES_BEFORE_RESIZE } from './max-scenes-before-resize.js'; export { MIN_SCENE_DURATION } from './min-scene-duration.constant.js'; -export { MIN_SCRIPT_DURATION } from './min-script-duration.constant.js'; export { NEW_SCRIPT_TEXT } from './new-script-text.constant.js'; export { SCRIPT_AND_AVATAR_ARE_REQUIRED } from './script-and-avatar-are-required.constant.js'; export { SKIP_TO_PREV_SCENE_THRESHOLD } from './skip-to-previous-scene-threshold.constant.js'; From d6049ab551a29ae3d0845ad40ffda760ff48e686 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 17:25:08 +0200 Subject: [PATCH 13/18] OV-415: * set min scene duration --- frontend/src/bundles/studio/store/slice.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/bundles/studio/store/slice.ts b/frontend/src/bundles/studio/store/slice.ts index 8755b58fe..3be6fef09 100644 --- a/frontend/src/bundles/studio/store/slice.ts +++ b/frontend/src/bundles/studio/store/slice.ts @@ -9,9 +9,10 @@ import { type VideoPreview as VideoPreviewT, } from '~/bundles/common/types/types.js'; import { + DEFAULT_SCENE_DURATION, + DEFAULT_SCRIPT_DURATION, DEFAULT_VOICE, MIN_SCENE_DURATION, - MIN_SCRIPT_DURATION, } from '~/bundles/studio/constants/constants.js'; import { type MenuItems, PlayIconNames, RowNames } from '../enums/enums.js'; @@ -102,7 +103,7 @@ const initialState: State = { elapsedTime: 0, }, range: { start: 0, end: minutesToMilliseconds(1) }, - scenes: [{ id: uuidv4(), duration: MIN_SCENE_DURATION }], + scenes: [{ id: uuidv4(), duration: DEFAULT_SCENE_DURATION }], scripts: [], selectedScriptId: null, videoSize: VideoPreview.LANDSCAPE, @@ -129,7 +130,7 @@ const { reducer, actions, name } = createSlice({ addScript(state, action: PayloadAction) { const script = { id: uuidv4(), - duration: MIN_SCRIPT_DURATION, + duration: DEFAULT_SCRIPT_DURATION, text: action.payload, voice: DEFAULT_VOICE, iconName: PlayIconNames.READY, @@ -194,7 +195,7 @@ const { reducer, actions, name } = createSlice({ addScene(state) { const scene = { id: uuidv4(), - duration: MIN_SCENE_DURATION, + duration: DEFAULT_SCENE_DURATION, }; state.ui.selectedItem = { id: scene.id, type: RowNames.SCENE }; state.scenes.push(scene); @@ -212,7 +213,11 @@ const { reducer, actions, name } = createSlice({ return item; } - const duration = millisecondsToSeconds(span.end - span.start); + let duration = millisecondsToSeconds(span.end - span.start); + + if (duration < MIN_SCENE_DURATION) { + duration = MIN_SCENE_DURATION; + } return { ...item, From 2a0c8fa9c76b05c43f88acd67ef8e2b9bffe9983 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 17:31:36 +0200 Subject: [PATCH 14/18] OV-415: * resizing stops at min duration --- .../studio/components/timeline/timeline.tsx | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/studio/components/timeline/timeline.tsx b/frontend/src/bundles/studio/components/timeline/timeline.tsx index 0f5a3628f..4dbf58f55 100644 --- a/frontend/src/bundles/studio/components/timeline/timeline.tsx +++ b/frontend/src/bundles/studio/components/timeline/timeline.tsx @@ -1,10 +1,12 @@ import { PointerSensor, useSensor, useSensors } from '@dnd-kit/core'; import { type PlayerRef } from '@remotion/player'; +import { secondsToMilliseconds } from 'date-fns'; import { type DragEndEvent, type DragMoveEvent, type Range, type ResizeEndEvent, + type ResizeMoveEvent, TimelineContext, } from 'dnd-timeline'; import { type RefObject } from 'react'; @@ -14,7 +16,10 @@ import { useAppSelector, useCallback, } from '~/bundles/common/hooks/hooks.js'; -import { DND_ACTIVATION_DISTANCE_PIXELS } from '~/bundles/studio/constants/constants.js'; +import { + DND_ACTIVATION_DISTANCE_PIXELS, + MIN_SCENE_DURATION, +} from '~/bundles/studio/constants/constants.js'; import { RowNames } from '~/bundles/studio/enums/row-names.enum.js'; import { actions as studioActions } from '~/bundles/studio/store/studio.js'; import { type RowType } from '~/bundles/studio/types/types.js'; @@ -57,6 +62,42 @@ const Timeline: React.FC = ({ playerRef }) => { [dispatch], ); + const handleResizing = useCallback( + (event: ResizeMoveEvent): void => { + const activeItem = event.active.data.current; + const activeItemType = activeItem['type'] as RowType; + + const updatedSpan = activeItem.getSpanFromResizeEvent?.(event); + + if ( + !updatedSpan || + activeItemType === RowNames.SCRIPT || + activeItemType === RowNames.BUTTON + ) { + return; + } + + if ( + updatedSpan.end - updatedSpan.start < + secondsToMilliseconds(MIN_SCENE_DURATION) + ) { + updatedSpan.end = + updatedSpan.start + + secondsToMilliseconds(MIN_SCENE_DURATION); + + const activeItemId = event.active.id as string; + + dispatch( + studioActions.resizeScene({ + id: activeItemId, + span: updatedSpan, + }), + ); + } + }, + [dispatch], + ); + const handleDragMove = useCallback( (event: DragMoveEvent) => { const activeItem = event.active.data.current; @@ -149,6 +190,7 @@ const Timeline: React.FC = ({ playerRef }) => { Date: Tue, 24 Sep 2024 18:56:08 +0200 Subject: [PATCH 15/18] OV-418: * add `none` buttons to background choices --- .../backgrounds-content/backgrounds-content.tsx | 14 ++++++++++++++ .../backgrounds-content/styles.module.css | 15 +++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx index e4c0fe3f5..7c13aa56c 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx @@ -1,16 +1,19 @@ import { + Flex, SimpleGrid, Tab, TabList, TabPanel, TabPanels, Tabs, + Text, } from '~/bundles/common/components/components.js'; // TODO: Make endpoint for this import backgroundColors from '~/bundles/studio/data/bg-colors.json'; import backgroundImages from '~/bundles/studio/data/bg-images.json'; import { ColorCard, ImageCard } from './components/components.js'; +import styles from './styles.module.css'; const BackgroundsContent: React.FC = () => { return ( @@ -24,6 +27,13 @@ const BackgroundsContent: React.FC = () => { + + None + + {backgroundImages.map((imageSource, index) => ( { + + None + + {backgroundColors.map((color, index) => ( ))} diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css new file mode 100644 index 000000000..ea3d7ebcc --- /dev/null +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css @@ -0,0 +1,15 @@ +.none-item { + background-color: var(--chakra-colors-background-700); + border-radius: 7px; + border-width: 1px; + border-color: transparent; + transition: all 0.3s ease; + align-items: center; + justify-content: center; +} + +.none-item:hover { + background-color: var(--chakra-colors-background-600); + border-color: var(--chakra-colors-brand-secondary-300); + cursor: 'pointer'; +} From 76282ce494f8f643ccedb6bc80de10ba7a8782e1 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 19:45:03 +0200 Subject: [PATCH 16/18] OV-418: * add reducer to remove bg --- frontend/src/bundles/studio/store/slice.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/frontend/src/bundles/studio/store/slice.ts b/frontend/src/bundles/studio/store/slice.ts index 8755b58fe..3df0969a1 100644 --- a/frontend/src/bundles/studio/store/slice.ts +++ b/frontend/src/bundles/studio/store/slice.ts @@ -346,6 +346,23 @@ const { reducer, actions, name } = createSlice({ }; }); }, + removeBackgroundFromScene(state) { + const selectedItem = state.ui.selectedItem; + if (!selectedItem || selectedItem.type !== RowNames.SCENE) { + return; + } + + state.scenes = state.scenes.map((scene) => { + if (scene.id !== selectedItem.id) { + return scene; + } + + return { + ...scene, + background: {}, + }; + }); + }, setMenuActiveItem( state, action: PayloadAction | null>, From 4cf3df764569e3746f8d2b826d697f9236d4e538 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 19:46:44 +0200 Subject: [PATCH 17/18] OV-418: * handle remove bg --- .../backgrounds-content/backgrounds-content.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx index 7c13aa56c..b0cc6af44 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/backgrounds-content.tsx @@ -8,14 +8,21 @@ import { Tabs, Text, } from '~/bundles/common/components/components.js'; +import { useAppDispatch, useCallback } from '~/bundles/common/hooks/hooks.js'; // TODO: Make endpoint for this import backgroundColors from '~/bundles/studio/data/bg-colors.json'; import backgroundImages from '~/bundles/studio/data/bg-images.json'; +import { actions as studioActions } from '~/bundles/studio/store/studio.js'; import { ColorCard, ImageCard } from './components/components.js'; import styles from './styles.module.css'; const BackgroundsContent: React.FC = () => { + const dispatch = useAppDispatch(); + const handleRemoveBackground = useCallback((): void => { + dispatch(studioActions.removeBackgroundFromScene()); + }, [dispatch]); + return ( <> @@ -30,6 +37,7 @@ const BackgroundsContent: React.FC = () => { None @@ -44,7 +52,11 @@ const BackgroundsContent: React.FC = () => { - + None From b50913f422af8566f5dc62fdaba8a966bb55c031 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 24 Sep 2024 19:48:26 +0200 Subject: [PATCH 18/18] OV-418: * fix styles --- .../backgrounds-content/components/color-card.tsx | 4 +++- .../components/styles.module.css | 15 ++++++++++++++- .../backgrounds-content/styles.module.css | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/color-card.tsx b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/color-card.tsx index 5ceaabb4a..f1680fef2 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/color-card.tsx +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/color-card.tsx @@ -2,6 +2,8 @@ import { Box } from '~/bundles/common/components/components.js'; import { useAppDispatch, useCallback } from '~/bundles/common/hooks/hooks.js'; import { actions as studioActions } from '~/bundles/studio/store/studio.js'; +import styles from './styles.module.css'; + type Properties = { color: string; }; @@ -20,8 +22,8 @@ const ColorCard: React.FC = ({ color }) => { return ( ); diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/styles.module.css b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/styles.module.css index 4416b5f25..add5f9567 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/styles.module.css +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/components/styles.module.css @@ -7,8 +7,21 @@ transition: all 0.3s ease; } +.color-item { + border-radius: 7px; + height: 80px; + border-width: 1px; + border-color: transparent; + transition: all 0.3s ease; +} + .image-item:hover { background-color: var(--chakra-colors-background-600); border-color: var(--chakra-colors-brand-secondary-300); - cursor: 'pointer'; + cursor: pointer; +} + +.color-item:hover { + border-color: var(--chakra-colors-brand-secondary-300); + cursor: pointer; } diff --git a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css index ea3d7ebcc..d20a3d960 100644 --- a/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css +++ b/frontend/src/bundles/studio/components/video-menu/components/menu-content/backgrounds-content/styles.module.css @@ -11,5 +11,5 @@ .none-item:hover { background-color: var(--chakra-colors-background-600); border-color: var(--chakra-colors-brand-secondary-300); - cursor: 'pointer'; + cursor: pointer; }