From 0dd60553dab47c7f7457ebfaa823be4c2a7d39b2 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 09:27:00 -0500 Subject: [PATCH 01/22] OV-402: + create avatars page components --- .../components/avatar-card/avatar-card.tsx | 42 ++++++++++ .../avatars-library/avatars-library.tsx | 82 +++++++++++++++++++ .../ai-avatars/components/avatars/avatars.tsx | 21 +++++ .../ai-avatars/components/components.ts | 3 + 4 files changed, 148 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx create mode 100644 frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx create mode 100644 frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx create mode 100644 frontend/src/bundles/ai-avatars/components/components.ts diff --git a/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx b/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx new file mode 100644 index 000000000..84fd47cef --- /dev/null +++ b/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx @@ -0,0 +1,42 @@ +import { + Box, + Card, + CardBody, + Flex, + Image, + Tag, + Text, +} from '~/bundles/common/components/components.js'; + +type Properties = { + image: string; + name: string; + tag: string; +}; + +const AvatarCard: React.FC = ({ image, name, tag }) => { + return ( + + + + AI generated avatar image + + + + {name} + + + + {tag} + + + 4K + + + + + + ); +}; + +export { AvatarCard }; diff --git a/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx b/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx new file mode 100644 index 000000000..1501783f4 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx @@ -0,0 +1,82 @@ +import { + Box, + Flex, + FormProvider, + Loader, + Select, + SimpleGrid, + Text, +} from '~/bundles/common/components/components.js'; +import { DataStatus } from '~/bundles/common/enums/data-status.enum.js'; +import { + useAppDispatch, + useAppForm, + useAppSelector, + useEffect, +} from '~/bundles/common/hooks/hooks.js'; +import { actions as studioActions } from '~/bundles/studio/store/studio.js'; + +import { useFilterAvatarStyle } from '../../hooks/use-filter-avatar-style.hook.js'; +import { AvatarCard } from '../components.js'; + +const AvatarsLibrary: React.FC = () => { + const dispatch = useAppDispatch(); + const { dataStatus } = useAppSelector(({ studio }) => studio); + const form = useAppForm<{ style: string }>({ + initialValues: { style: '' }, + }); + + const { + values: { style }, + } = form; + + const avatars = useFilterAvatarStyle(style); + + useEffect(() => { + if (avatars.length === 0) { + void dispatch(studioActions.loadAvatars()); + } + }, [dispatch, avatars.length]); + + return ( + <> + + OutreachVids Library + + + + + + + {dataStatus === DataStatus.PENDING ? ( + + + + ) : ( + + {avatars.map(({ id, imgUrl, name, style }) => ( + + ))} + + )} + + ); +}; + +export { AvatarsLibrary }; diff --git a/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx b/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx new file mode 100644 index 000000000..2617dd620 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx @@ -0,0 +1,21 @@ +import { Box, Text } from '~/bundles/common/components/components.js'; + +import { AvatarsLibrary } from '../components.js'; + +const Avatars: React.FC = () => { + return ( + + + AI Avatars + + + + ); +}; + +export { Avatars }; diff --git a/frontend/src/bundles/ai-avatars/components/components.ts b/frontend/src/bundles/ai-avatars/components/components.ts new file mode 100644 index 000000000..cfe44f39d --- /dev/null +++ b/frontend/src/bundles/ai-avatars/components/components.ts @@ -0,0 +1,3 @@ +export { AvatarCard } from './avatar-card/avatar-card.js'; +export { Avatars } from './avatars/avatars.js'; +export { AvatarsLibrary } from './avatars-library/avatars-library.js'; From 92640a8f75be52a1ac1610f567fef92bda2c3dee Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 09:28:31 -0500 Subject: [PATCH 02/22] OV-402: + create helpers --- .../helpers/avatars-mapper.helper.ts | 20 +++++++++++++++++++ .../ai-avatars/helpers/capital-case.helper.ts | 5 +++++ .../src/bundles/ai-avatars/helpers/helpers.ts | 2 ++ 3 files changed, 27 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts create mode 100644 frontend/src/bundles/ai-avatars/helpers/capital-case.helper.ts create mode 100644 frontend/src/bundles/ai-avatars/helpers/helpers.ts diff --git a/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts b/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts new file mode 100644 index 000000000..7b0055da9 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts @@ -0,0 +1,20 @@ +import { + type AvatarGetResponseDto, + type AvatarMapped, +} from '../types/types.js'; +import { capitalCase } from './helpers.js'; + +const avatarsMapper = (avatars: AvatarGetResponseDto[]): AvatarMapped[] => { + return avatars.flatMap(({ id, name, styles }) => { + return styles.map(({ imgUrl, style }) => { + return { + id, + name: capitalCase(name), + style: style.split('-')[0] as string, + imgUrl, + }; + }); + }); +}; + +export { avatarsMapper }; diff --git a/frontend/src/bundles/ai-avatars/helpers/capital-case.helper.ts b/frontend/src/bundles/ai-avatars/helpers/capital-case.helper.ts new file mode 100644 index 000000000..f3971c304 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/helpers/capital-case.helper.ts @@ -0,0 +1,5 @@ +const capitalCase = (name: string): string => { + return name.charAt(0).toUpperCase() + name.slice(1); +}; + +export { capitalCase }; diff --git a/frontend/src/bundles/ai-avatars/helpers/helpers.ts b/frontend/src/bundles/ai-avatars/helpers/helpers.ts new file mode 100644 index 000000000..99e94d192 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/helpers/helpers.ts @@ -0,0 +1,2 @@ +export { avatarsMapper } from './avatars-mapper.helper.js'; +export { capitalCase } from './capital-case.helper.js'; From 116e63947063a48d22c9901f0f5c98eacfee6e25 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:39:45 -0500 Subject: [PATCH 03/22] OV-402: + create fliter hook --- .../hooks/use-filter-avatar-style.hook.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/hooks/use-filter-avatar-style.hook.ts diff --git a/frontend/src/bundles/ai-avatars/hooks/use-filter-avatar-style.hook.ts b/frontend/src/bundles/ai-avatars/hooks/use-filter-avatar-style.hook.ts new file mode 100644 index 000000000..7010635be --- /dev/null +++ b/frontend/src/bundles/ai-avatars/hooks/use-filter-avatar-style.hook.ts @@ -0,0 +1,30 @@ +import { + useAppSelector, + useEffect, + useState, +} from '~/bundles/common/hooks/hooks.js'; + +import { avatarsMapper } from '../helpers/helpers.js'; +import { type AvatarMapped } from '../types/types.js'; + +const useFilterAvatarStyle = (style: string): AvatarMapped[] => { + const { avatars } = useAppSelector(({ studio }) => studio); + const [avatarFiltered, setAvatarFiltered] = useState([]); + + useEffect(() => { + const avatarsMapped = avatarsMapper(avatars); + + const filterAvatars = (): AvatarMapped[] => + avatarsMapped.filter( + ({ style: avatarStyle }) => !style || avatarStyle === style, + ); + + const filteredAvatars = filterAvatars(); + + setAvatarFiltered(filteredAvatars); + }, [avatars, style]); + + return avatarFiltered; +}; + +export { useFilterAvatarStyle }; From 5c92a1de5e753019d90c0b346884fb9e4e6a018b Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:41:43 -0500 Subject: [PATCH 04/22] OV-402: + create avatars page --- .../src/bundles/ai-avatars/pages/ai-avatars.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/pages/ai-avatars.tsx diff --git a/frontend/src/bundles/ai-avatars/pages/ai-avatars.tsx b/frontend/src/bundles/ai-avatars/pages/ai-avatars.tsx new file mode 100644 index 000000000..363bdebfc --- /dev/null +++ b/frontend/src/bundles/ai-avatars/pages/ai-avatars.tsx @@ -0,0 +1,16 @@ +import { Header, Sidebar } from '~/bundles/common/components/components.js'; + +import { Avatars } from '../components/components.js'; + +const AIAvatars: React.FC = () => { + return ( + <> +
+ + + + + ); +}; + +export { AIAvatars }; From 31f7e919b59e73ce1bb5d04b094e86120f64c8db Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:43:52 -0500 Subject: [PATCH 05/22] OV-402: + add avatar types --- frontend/src/bundles/ai-avatars/types/avatar-mapped.ts | 8 ++++++++ frontend/src/bundles/ai-avatars/types/types.ts | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/types/avatar-mapped.ts create mode 100644 frontend/src/bundles/ai-avatars/types/types.ts diff --git a/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts b/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts new file mode 100644 index 000000000..29e47c6ef --- /dev/null +++ b/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts @@ -0,0 +1,8 @@ +type AvatarMapped = { + id: string; + name: string; + style: string; + imgUrl: string; +}; + +export { type AvatarMapped }; diff --git a/frontend/src/bundles/ai-avatars/types/types.ts b/frontend/src/bundles/ai-avatars/types/types.ts new file mode 100644 index 000000000..ee0907f40 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/types/types.ts @@ -0,0 +1,2 @@ +export { type AvatarMapped } from './avatar-mapped.js'; +export { type AvatarGetResponseDto } from 'shared'; From a87c9acf5af4bc9ad2774f62f52004280e9e92b9 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:45:40 -0500 Subject: [PATCH 06/22] OV-402: + add ai avatars item --- .../common/components/sidebar/sidebar.tsx | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/frontend/src/bundles/common/components/sidebar/sidebar.tsx b/frontend/src/bundles/common/components/sidebar/sidebar.tsx index 5b16eceb9..459cae42b 100644 --- a/frontend/src/bundles/common/components/sidebar/sidebar.tsx +++ b/frontend/src/bundles/common/components/sidebar/sidebar.tsx @@ -6,6 +6,7 @@ import { IconButton, Link, Spacer, + Text, } from '~/bundles/common/components/components.js'; import { AppRoute } from '~/bundles/common/enums/enums.js'; import { @@ -106,6 +107,28 @@ const Sidebar: React.FC = ({ children }) => { /> + + + Assets + + + + + + } + isCollapsed={isCollapsed} + label="AI Avatars" + /> + + + Date: Thu, 26 Sep 2024 10:47:26 -0500 Subject: [PATCH 07/22] OV-402: * make label optional --- frontend/src/bundles/common/components/select/select.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/bundles/common/components/select/select.tsx b/frontend/src/bundles/common/components/select/select.tsx index 20cce289c..480b0641f 100644 --- a/frontend/src/bundles/common/components/select/select.tsx +++ b/frontend/src/bundles/common/components/select/select.tsx @@ -13,9 +13,9 @@ import { import { useFormField } from '~/bundles/common/hooks/hooks.js'; type Properties = { - label: string; name: FieldInputProps['name']; children: React.ReactNode; + label?: string; isRequired?: boolean; placeholder?: string; }; From 4bd044c440f555ca578e07b52022944971a76fba Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:49:10 -0500 Subject: [PATCH 08/22] OV-402: + add tag component --- frontend/src/bundles/common/components/components.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/bundles/common/components/components.ts b/frontend/src/bundles/common/components/components.ts index 20ba7b934..5a4b887df 100644 --- a/frontend/src/bundles/common/components/components.ts +++ b/frontend/src/bundles/common/components/components.ts @@ -74,6 +74,7 @@ export { TabPanel, TabPanels, Tabs, + Tag, Text, Tooltip, UnorderedList, From a38db17f82bf8fab6489bfb74f92f97aa496e7d5 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:54:51 -0500 Subject: [PATCH 09/22] OV-402: + add ai avatars route --- frontend/src/bundles/common/enums/app-route.enum.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/bundles/common/enums/app-route.enum.ts b/frontend/src/bundles/common/enums/app-route.enum.ts index d6526128a..4b8ee49b8 100644 --- a/frontend/src/bundles/common/enums/app-route.enum.ts +++ b/frontend/src/bundles/common/enums/app-route.enum.ts @@ -6,6 +6,7 @@ const AppRoute = { MY_AVATAR: '/my-avatar', ANY: '*', CREATE_AVATAR: '/create-avatar', + AI_AVATARS: '/ai-avatars', } as const; export { AppRoute }; From ea1eda8a8f22b78dae1e5c30a23be543aa168dd0 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:56:58 -0500 Subject: [PATCH 10/22] OV-402: * make onsubmit optional --- .../bundles/common/hooks/use-app-form/use-app-form.hook.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/common/hooks/use-app-form/use-app-form.hook.ts b/frontend/src/bundles/common/hooks/use-app-form/use-app-form.hook.ts index 827d9e176..d7f8a0653 100644 --- a/frontend/src/bundles/common/hooks/use-app-form/use-app-form.hook.ts +++ b/frontend/src/bundles/common/hooks/use-app-form/use-app-form.hook.ts @@ -21,7 +21,7 @@ type Parameters = { initialValues: T; mode?: ValueOf; validationSchema?: ValidationSchema; - onSubmit: FormConfig['onSubmit']; + onSubmit?: FormConfig['onSubmit']; }; type ReturnValue = ReturnType< @@ -32,7 +32,9 @@ const useAppForm = ({ initialValues, mode = 'onSubmit', validationSchema, - onSubmit, + onSubmit = (values: T): void => { + values; + }, }: Parameters): ReturnValue => { const validateOnBlur = mode === ValidationMode.ALL ? true : mode === ValidationMode.ON_BLUR; From f87b43fc9cb6abbbe36db6b33d6e318d1f701d83 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 10:58:33 -0500 Subject: [PATCH 11/22] OV-402: + add avatar icon --- .../src/bundles/common/icons/helper/icon-conversion.helper.ts | 3 +++ frontend/src/bundles/common/icons/icon-name.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts index d4345bd27..06c982381 100644 --- a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts +++ b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts @@ -17,6 +17,7 @@ import { faStop, faT, faTableColumns, + faUserLarge, faVideoCamera, faVolumeHigh, faVolumeOff, @@ -45,8 +46,10 @@ const VolumeOff = convertIcon(faVolumeOff); const Stop = convertIcon(faStop); const VideoCamera = convertIcon(faVideoCamera); const Image = convertIcon(faImage); +const AIAvatars = convertIcon(faUserLarge); export { + AIAvatars, BackwardStep, CircleUser, CloudArrowDown, diff --git a/frontend/src/bundles/common/icons/icon-name.ts b/frontend/src/bundles/common/icons/icon-name.ts index 729172418..437c89e48 100644 --- a/frontend/src/bundles/common/icons/icon-name.ts +++ b/frontend/src/bundles/common/icons/icon-name.ts @@ -14,6 +14,7 @@ import { import { Logo, LogoText, OpenAi } from './custom-icons/custom-icons.js'; import { + AIAvatars, BackwardStep, CircleUser, CloudArrowDown, @@ -38,6 +39,7 @@ import { } from './helper/icon-conversion.helper.js'; const IconName = { + AI_AVATARS: AIAvatars, CHEVRON_DOWN: ChevronDownIcon, PEN: Pen, HOME: House, From f29b8c00c0c740488af7e9674341ff3df851e8f2 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 11:01:09 -0500 Subject: [PATCH 12/22] OV-402: + add transparent color --- frontend/src/framework/theme/styles/colors.styles.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/framework/theme/styles/colors.styles.ts b/frontend/src/framework/theme/styles/colors.styles.ts index 95d090632..8ad91a57c 100644 --- a/frontend/src/framework/theme/styles/colors.styles.ts +++ b/frontend/src/framework/theme/styles/colors.styles.ts @@ -6,6 +6,7 @@ const colors = { 700: '#231B59', 600: '#35399a', 300: '#3c9cf5', + 330: '#3c9cf530', 50: '#e2e1ec', }, brand: { From d2882adfae39847b5f781adeea91a420ff55e7e2 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 11:02:53 -0500 Subject: [PATCH 13/22] OV-402: + add ai page to route system --- frontend/src/routes/routes.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/src/routes/routes.tsx b/frontend/src/routes/routes.tsx index 1a6e2e18d..58b517245 100644 --- a/frontend/src/routes/routes.tsx +++ b/frontend/src/routes/routes.tsx @@ -1,4 +1,5 @@ import { App } from '~/app/app.js'; +import { AIAvatars } from '~/bundles/ai-avatars/pages/ai-avatars.js'; import { Auth } from '~/bundles/auth/pages/auth.js'; import { ProtectedRoute } from '~/bundles/common/components/components.js'; import { AppRoute } from '~/bundles/common/enums/enums.js'; @@ -53,6 +54,14 @@ const routes = [ ), }, + { + path: AppRoute.AI_AVATARS, + element: ( + + + + ), + }, { path: AppRoute.ANY, element: , From 852885198a4ab0c197f6685f866bf8f852605221 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:24:41 -0500 Subject: [PATCH 14/22] OV-402: + add toggle like action --- frontend/src/bundles/studio/store/slice.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/frontend/src/bundles/studio/store/slice.ts b/frontend/src/bundles/studio/store/slice.ts index 8755b58fe..43abe226b 100644 --- a/frontend/src/bundles/studio/store/slice.ts +++ b/frontend/src/bundles/studio/store/slice.ts @@ -386,6 +386,26 @@ const { reducer, actions, name } = createSlice({ }, ); }, + avatarLikeToggle( + state, + action: PayloadAction<{ avatarId: string; image: string }>, + ) { + const { avatarId, image } = action.payload; + + const avatar = state.avatars.find(({ id }) => id === avatarId); + + if (!avatar) { + return; + } + + const style = avatar.styles.find(({ imgUrl }) => imgUrl === image); + + if (!style) { + return; + } + + style.isLiked = !style.isLiked; + }, }, extraReducers(builder) { builder.addCase(loadAvatars.pending, (state) => { From 25b0f2b8df824263ca8c72281b562c7e58cac9e4 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:26:21 -0500 Subject: [PATCH 15/22] OV-402: + heart icon --- .../src/bundles/common/icons/helper/icon-conversion.helper.ts | 3 +++ frontend/src/bundles/common/icons/icon-name.ts | 2 ++ 2 files changed, 5 insertions(+) diff --git a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts index 06c982381..d8344fd2d 100644 --- a/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts +++ b/frontend/src/bundles/common/icons/helper/icon-conversion.helper.ts @@ -7,6 +7,7 @@ import { faFileLines, faFont, faForwardStep, + faHeart, faHouse, faImage, faPause, @@ -47,6 +48,7 @@ const Stop = convertIcon(faStop); const VideoCamera = convertIcon(faVideoCamera); const Image = convertIcon(faImage); const AIAvatars = convertIcon(faUserLarge); +const Heart = convertIcon(faHeart); export { AIAvatars, @@ -58,6 +60,7 @@ export { FileLines, Font, ForwardStep, + Heart, House, Image, Pause, diff --git a/frontend/src/bundles/common/icons/icon-name.ts b/frontend/src/bundles/common/icons/icon-name.ts index 437c89e48..bbe6a6d55 100644 --- a/frontend/src/bundles/common/icons/icon-name.ts +++ b/frontend/src/bundles/common/icons/icon-name.ts @@ -23,6 +23,7 @@ import { FileLines, Font, ForwardStep, + Heart, House, Image, Pause, @@ -75,6 +76,7 @@ const IconName = { WARNING: WarningIcon, VIDEO_CAMERA: VideoCamera, IMAGE: Image, + HEART: Heart, } as const; export { IconName }; From f806c78a3c470612be256691eb4d0b93aa77fbf3 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:29:10 -0500 Subject: [PATCH 16/22] OV-402: + add isLike property --- shared/src/bundles/avatars/types/avatar-get-response-dto.type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/shared/src/bundles/avatars/types/avatar-get-response-dto.type.ts b/shared/src/bundles/avatars/types/avatar-get-response-dto.type.ts index e9dcadceb..6a9579850 100644 --- a/shared/src/bundles/avatars/types/avatar-get-response-dto.type.ts +++ b/shared/src/bundles/avatars/types/avatar-get-response-dto.type.ts @@ -7,6 +7,7 @@ type AvatarGetResponseDto = { imgUrl: string; style: string; gestures: string[]; + isLiked?: boolean; }[]; }; From dbe1b229c78b5691183bb4ac4090ae57f0df5457 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:31:48 -0500 Subject: [PATCH 17/22] OV-402: + add isLike property --- .../src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts | 3 ++- frontend/src/bundles/ai-avatars/types/avatar-mapped.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts b/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts index 7b0055da9..efc4286e1 100644 --- a/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts +++ b/frontend/src/bundles/ai-avatars/helpers/avatars-mapper.helper.ts @@ -6,12 +6,13 @@ import { capitalCase } from './helpers.js'; const avatarsMapper = (avatars: AvatarGetResponseDto[]): AvatarMapped[] => { return avatars.flatMap(({ id, name, styles }) => { - return styles.map(({ imgUrl, style }) => { + return styles.map(({ imgUrl, style, isLiked }) => { return { id, name: capitalCase(name), style: style.split('-')[0] as string, imgUrl, + isLiked, }; }); }); diff --git a/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts b/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts index 29e47c6ef..b5868d916 100644 --- a/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts +++ b/frontend/src/bundles/ai-avatars/types/avatar-mapped.ts @@ -3,6 +3,7 @@ type AvatarMapped = { name: string; style: string; imgUrl: string; + isLiked: boolean | undefined; }; export { type AvatarMapped }; From f51fe8f91e94a7ee6686157ae9fcb9101c8bbc65 Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:34:17 -0500 Subject: [PATCH 18/22] OV-402: + add constant --- frontend/src/bundles/ai-avatars/constants/constants.ts | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/constants/constants.ts diff --git a/frontend/src/bundles/ai-avatars/constants/constants.ts b/frontend/src/bundles/ai-avatars/constants/constants.ts new file mode 100644 index 000000000..3e9ba6bd7 --- /dev/null +++ b/frontend/src/bundles/ai-avatars/constants/constants.ts @@ -0,0 +1,3 @@ +const EMPTY_LENGTH = 0; + +export { EMPTY_LENGTH }; From fc624fc81f89a63483f6b43c59f4d7220e5a65ee Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:37:17 -0500 Subject: [PATCH 19/22] OV-402: + add heart button --- .../components/avatar-card/avatar-card.tsx | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx b/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx index 84fd47cef..a3bebefbc 100644 --- a/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx +++ b/frontend/src/bundles/ai-avatars/components/avatar-card/avatar-card.tsx @@ -3,23 +3,57 @@ import { Card, CardBody, Flex, + Icon, + IconButton, Image, Tag, Text, } from '~/bundles/common/components/components.js'; +import { useAppDispatch, useCallback } from '~/bundles/common/hooks/hooks.js'; +import { IconName } from '~/bundles/common/icons/icon-name.js'; +import { actions as studioActions } from '~/bundles/studio/store/slice.js'; type Properties = { + id: string; image: string; name: string; tag: string; + isLiked: boolean | undefined; }; -const AvatarCard: React.FC = ({ image, name, tag }) => { +const AvatarCard: React.FC = ({ + id, + image, + name, + tag, + isLiked, +}) => { + const dispatch = useAppDispatch(); + + const handleLike = useCallback(() => { + dispatch( + studioActions.avatarLikeToggle({ + avatarId: id, + image, + }), + ); + }, [dispatch, id, image]); + return ( - + AI generated avatar image + } + color={isLiked ? 'brand.secondary.300' : 'white'} + variant="icon" + position="absolute" + top="0" + right="0" + onClick={handleLike} + /> From c1f322f3c6960caf03fca7d59f3d5acce90dbb0e Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:41:23 -0500 Subject: [PATCH 20/22] OV-402: + filters logic --- .../ai-avatars/components/avatars/avatars.tsx | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx b/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx index 2617dd620..e999b8ae5 100644 --- a/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx +++ b/frontend/src/bundles/ai-avatars/components/avatars/avatars.tsx @@ -1,8 +1,42 @@ -import { Box, Text } from '~/bundles/common/components/components.js'; +import { EMPTY_LENGTH } from '~/bundles/ai-avatars/constants/constants.js'; +import { avatarsMapper } from '~/bundles/ai-avatars/helpers/helpers.js'; +import { useFilterAvatarStyle } from '~/bundles/ai-avatars/hooks/use-filter-avatar-style.hook.js'; +import { Box, Heading } from '~/bundles/common/components/components.js'; +import { + useAppDispatch, + useAppForm, + useAppSelector, + useEffect, + useMemo, +} from '~/bundles/common/hooks/hooks.js'; +import { actions as studioActions } from '~/bundles/studio/store/studio.js'; -import { AvatarsLibrary } from '../components.js'; +import { AvatarsSection } from '../components.js'; const Avatars: React.FC = () => { + const dispatch = useAppDispatch(); + const { avatars } = useAppSelector(({ studio }) => studio); + + const form = useAppForm<{ style: string }>({ + initialValues: { style: '' }, + }); + const { + values: { style }, + } = form; + + const styledAvatars = useFilterAvatarStyle(style); + const mappedAvatars = useMemo(() => avatarsMapper(avatars), [avatars]); + const favoriteAvatars = useMemo( + () => mappedAvatars.filter(({ isLiked }) => isLiked), + [mappedAvatars], + ); + + useEffect(() => { + if (avatars.length === EMPTY_LENGTH) { + void dispatch(studioActions.loadAvatars()); + } + }, [dispatch, avatars.length]); + return ( { p="25px" minH="calc(100vh - 75px)" > - AI Avatars - + + AI Avatars + + + ); From 89f4f5c6eac4818e59bc1621c840b2516c5631da Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:46:43 -0500 Subject: [PATCH 21/22] OV-402: + conditional rendering --- .../avatars-section/avatars-section.tsx | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 frontend/src/bundles/ai-avatars/components/avatars-section/avatars-section.tsx diff --git a/frontend/src/bundles/ai-avatars/components/avatars-section/avatars-section.tsx b/frontend/src/bundles/ai-avatars/components/avatars-section/avatars-section.tsx new file mode 100644 index 000000000..884a1f52c --- /dev/null +++ b/frontend/src/bundles/ai-avatars/components/avatars-section/avatars-section.tsx @@ -0,0 +1,86 @@ +import { type FormikProps } from 'formik'; + +import { EMPTY_LENGTH } from '~/bundles/ai-avatars/constants/constants.js'; +import { type AvatarMapped } from '~/bundles/ai-avatars/types/types.js'; +import { + Badge, + Box, + Flex, + FormProvider, + Heading, + Select, + SimpleGrid, + Text, +} from '~/bundles/common/components/components.js'; + +import { AvatarCard } from '../components.js'; + +type Properties = { + subtitle: string; + avatars: AvatarMapped[]; + form?: FormikProps<{ style: string }>; +}; + +const AvatarsSection: React.FC = ({ subtitle, avatars, form }) => { + return ( + + + + + {subtitle} + + + {avatars.length} + + + {form && ( + + + + + + )} + + {avatars.length === EMPTY_LENGTH && !form ? ( + + Pick your favorites avatars to show them here! + + ) : ( + + {avatars.map(({ id, imgUrl, name, style, isLiked }) => ( + + ))} + + )} + + ); +}; + +export { AvatarsSection }; From 4370fc00f14edae654b29b96c839d1f285b27fec Mon Sep 17 00:00:00 2001 From: JKaypa Date: Thu, 26 Sep 2024 20:49:32 -0500 Subject: [PATCH 22/22] OV-402: + export component --- .../avatars-library/avatars-library.tsx | 82 ------------------- .../ai-avatars/components/components.ts | 2 +- 2 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx diff --git a/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx b/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx deleted file mode 100644 index 1501783f4..000000000 --- a/frontend/src/bundles/ai-avatars/components/avatars-library/avatars-library.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { - Box, - Flex, - FormProvider, - Loader, - Select, - SimpleGrid, - Text, -} from '~/bundles/common/components/components.js'; -import { DataStatus } from '~/bundles/common/enums/data-status.enum.js'; -import { - useAppDispatch, - useAppForm, - useAppSelector, - useEffect, -} from '~/bundles/common/hooks/hooks.js'; -import { actions as studioActions } from '~/bundles/studio/store/studio.js'; - -import { useFilterAvatarStyle } from '../../hooks/use-filter-avatar-style.hook.js'; -import { AvatarCard } from '../components.js'; - -const AvatarsLibrary: React.FC = () => { - const dispatch = useAppDispatch(); - const { dataStatus } = useAppSelector(({ studio }) => studio); - const form = useAppForm<{ style: string }>({ - initialValues: { style: '' }, - }); - - const { - values: { style }, - } = form; - - const avatars = useFilterAvatarStyle(style); - - useEffect(() => { - if (avatars.length === 0) { - void dispatch(studioActions.loadAvatars()); - } - }, [dispatch, avatars.length]); - - return ( - <> - - OutreachVids Library - - - - - - - {dataStatus === DataStatus.PENDING ? ( - - - - ) : ( - - {avatars.map(({ id, imgUrl, name, style }) => ( - - ))} - - )} - - ); -}; - -export { AvatarsLibrary }; diff --git a/frontend/src/bundles/ai-avatars/components/components.ts b/frontend/src/bundles/ai-avatars/components/components.ts index cfe44f39d..c38154090 100644 --- a/frontend/src/bundles/ai-avatars/components/components.ts +++ b/frontend/src/bundles/ai-avatars/components/components.ts @@ -1,3 +1,3 @@ export { AvatarCard } from './avatar-card/avatar-card.js'; export { Avatars } from './avatars/avatars.js'; -export { AvatarsLibrary } from './avatars-library/avatars-library.js'; +export { AvatarsSection } from './avatars-section/avatars-section.js';