Skip to content

Commit

Permalink
Merge pull request #451 from BinaryStudioAcademy/task/OV-421-add-temp…
Browse files Browse the repository at this point in the history
…lates-menu

OV-421: Add templates menu
  • Loading branch information
nikita-remeslov authored Sep 27, 2024
2 parents 5d80b99 + ab0b83d commit 231d164
Show file tree
Hide file tree
Showing 40 changed files with 513 additions and 115 deletions.
2 changes: 1 addition & 1 deletion backend/src/bundles/templates/enums/enums.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { templateErrorMessage } from './template-error-message.enum.js';
export { templateApiPath } from './templates-api-path.enum.js';
export { TemplateApiPath } from 'shared';
14 changes: 7 additions & 7 deletions backend/src/bundles/templates/templates.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { ApiPath } from '~/common/enums/enums.js';
import { HTTPCode, HTTPMethod } from '~/common/http/http.js';
import { type Logger } from '~/common/logger/logger.js';

import { templateApiPath } from './enums/enums.js';
import { TemplateApiPath } from './enums/enums.js';
import { type TemplateService } from './templates.service.js';
import {
type CreateTemplateRequestDto,
Expand Down Expand Up @@ -111,7 +111,7 @@ class TemplateController extends BaseController {
this.templateService = templateService;

this.addRoute({
path: templateApiPath.USER,
path: TemplateApiPath.USER,
method: HTTPMethod.GET,
handler: (options) =>
this.findAllByUser(
Expand All @@ -122,15 +122,15 @@ class TemplateController extends BaseController {
});

this.addRoute({
path: templateApiPath.PUBLIC,
path: TemplateApiPath.PUBLIC,
method: HTTPMethod.GET,
handler: () => {
return this.findPublicTemplates();
},
});

this.addRoute({
path: templateApiPath.ID,
path: TemplateApiPath.ID,
method: HTTPMethod.GET,
handler: (options) => {
return this.findById(
Expand All @@ -142,7 +142,7 @@ class TemplateController extends BaseController {
});

this.addRoute({
path: templateApiPath.ROOT,
path: TemplateApiPath.ROOT,
method: HTTPMethod.POST,
validation: {
body: createTemplateValidationSchema,
Expand All @@ -156,7 +156,7 @@ class TemplateController extends BaseController {
});

this.addRoute({
path: templateApiPath.ID,
path: TemplateApiPath.ID,
method: HTTPMethod.PATCH,
validation: {
body: updateTemplateValidationSchema,
Expand All @@ -172,7 +172,7 @@ class TemplateController extends BaseController {
});

this.addRoute({
path: templateApiPath.ID,
path: TemplateApiPath.ID,
method: HTTPMethod.DELETE,
handler: (options) =>
this.delete(
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/bundles/common/middlewares/draft.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ const CHANGE_DRAFT_ACTIONS = new Set<string>([
studioActions.resizeScene.type,
studioActions.setVideoName.type,
studioActions.setVideoSize.type,
studioActions.addBackgroundToScene.type,
studioActions.loadTemplate.type,
]);

const isChangeDraftAction = (action: Action): boolean => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ 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 { BackgroundImageCard, ColorCard } from './components/components.js';
import styles from './styles.module.css';

const BackgroundsContent: React.FC = () => {
Expand Down Expand Up @@ -43,7 +43,7 @@ const BackgroundsContent: React.FC = () => {
</Flex>

{backgroundImages.map((imageSource, index) => (
<ImageCard
<BackgroundImageCard
key={index}
imageSource={imageSource}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { ColorCard } from './color-card.js';
export { ImageCard } from './image-card.js';
export { BackgroundImageCard } from './image-card.js';
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Box, Image } from '~/bundles/common/components/components.js';
import { useAppDispatch, useCallback } from '~/bundles/common/hooks/hooks.js';
import { ImageCard } from '~/bundles/studio/components/video-menu/components/menu-content/components/components.js';
import { actions as studioActions } from '~/bundles/studio/store/studio.js';

import styles from './styles.module.css';

type Properties = {
imageSource: string;
};

const ImageCard: React.FC<Properties> = ({ imageSource }) => {
const BackgroundImageCard: React.FC<Properties> = ({ imageSource }) => {
const dispatch = useAppDispatch();

const handleImageClick = useCallback((): void => {
Expand All @@ -20,16 +18,7 @@ const ImageCard: React.FC<Properties> = ({ imageSource }) => {
);
}, [dispatch, imageSource]);

return (
<Box className={styles['image-item']} onClick={handleImageClick}>
<Image
src={imageSource}
objectFit="contain"
width="100%"
height="100%"
></Image>
</Box>
);
return <ImageCard imageSource={imageSource} onClick={handleImageClick} />;
};

export { ImageCard };
export { BackgroundImageCard };
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
.image-item {
height: 100px;
background-color: var(--chakra-colors-background-700);
border-radius: 7px;
border-width: 1px;
border-color: transparent;
transition: all 0.3s ease;
}

.color-item {
border-radius: 7px;
height: 80px;
Expand All @@ -15,12 +6,6 @@
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;
}

.color-item:hover {
border-color: var(--chakra-colors-brand-secondary-300);
cursor: pointer;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ImageCard } from './image-card/image-card.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Box, Image } from '~/bundles/common/components/components.js';

import styles from './styles.module.css';

type Properties = {
imageSource: string;
onClick?: () => void;
};

const ImageCard: React.FC<Properties> = ({ imageSource, onClick }) => {
return (
<Box className={styles['image-item']} onClick={onClick}>
<Image
src={imageSource}
objectFit="contain"
width="100%"
height="100%"
></Image>
</Box>
);
};

export { ImageCard };
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.image-item {
height: 100px;
background-color: var(--chakra-colors-background-700);
border-radius: 7px;
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;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { AvatarsContent } from './avatars-content/avatars-content.js';
export { BackgroundsContent } from './backgrounds-content/backgrounds-content.js';
export { ScriptContent } from './script-content/script-content.js';
export { TemplatesContent } from './templates-content/templates-content.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { TemplateCard } from './template-card.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useAppDispatch, useCallback } from '~/bundles/common/hooks/hooks.js';
import { ImageCard } from '~/bundles/studio/components/video-menu/components/menu-content/components/components.js';
import { actions as studioActions } from '~/bundles/studio/store/studio.js';
import { type Template } from '~/bundles/studio/types/types.js';

type Properties = {
template: Template;
};

const TemplateCard: React.FC<Properties> = ({ template }) => {
const dispatch = useAppDispatch();

const handleClick = useCallback((): void => {
void dispatch(studioActions.loadTemplate(template));
}, [dispatch, template]);

return (
<ImageCard imageSource={template.previewUrl} onClick={handleClick} />
);
};

export { TemplateCard };
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
Box,
Loader,
SimpleGrid,
Tab,
TabList,
TabPanel,
TabPanels,
Tabs,
Text,
} from '~/bundles/common/components/components.js';
import { EMPTY_VALUE } from '~/bundles/common/constants/constants.js';
import { DataStatus } from '~/bundles/common/enums/data-status.enum.js';
import {
useAppDispatch,
useAppSelector,
useEffect,
} from '~/bundles/common/hooks/hooks.js';
import { actions as studioActions } from '~/bundles/studio/store/studio.js';

import { TemplateCard } from './components/components.js';

const TemplatesContent: React.FC = () => {
const dispatch = useAppDispatch();

const { templates, dataStatus } = useAppSelector(({ studio }) => studio);

useEffect(() => {
if (templates.public.length === EMPTY_VALUE) {
void dispatch(studioActions.loadPublicTemplates());
}
if (!templates.isUserLoaded) {
void dispatch(studioActions.loadUserTemplates());
}
}, [dispatch, templates]);

return (
<Tabs>
<TabList>
<Tab>Templates</Tab>
<Tab>My templates</Tab>
</TabList>

{dataStatus === DataStatus.PENDING ? (
<Box mt="100px">
<Loader />
</Box>
) : (
<TabPanels>
<TabPanel>
<SimpleGrid columns={2} spacingX="13px" spacingY="10px">
{templates.public.map((template) => (
<TemplateCard
key={template.id}
template={template}
/>
))}
</SimpleGrid>
</TabPanel>
<TabPanel>
{templates.user.length > EMPTY_VALUE ? (
<SimpleGrid
columns={2}
spacingX="13px"
spacingY="10px"
>
{templates.user.map((template) => (
<TemplateCard
key={template.id}
template={template}
/>
))}
</SimpleGrid>
) : (
<Text color="typography.600" variant="body1">
You have no templates yet.
</Text>
)}
</TabPanel>
</TabPanels>
)}
</Tabs>
);
};

export { TemplatesContent };
11 changes: 6 additions & 5 deletions frontend/src/bundles/studio/components/video-menu/video-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
AvatarsContent,
BackgroundsContent,
ScriptContent,
TemplatesContent,
} from './components/menu-content/content.js';
// import {
// AssetsContent,
Expand Down Expand Up @@ -66,11 +67,11 @@ const VideoMenu: React.FC = () => {

// TODO: Uncomment menu items after demo
const menuItems: Record<ValueOf<typeof MenuItems>, MenuItem> = {
// templates: {
// label: 'Templates',
// icon: <Icon as={IconName.TEMPLATE} />,
// getContent: () => <TemplatesContent />,
// },
templates: {
label: 'Templates',
icon: <Icon as={IconName.TEMPLATE} />,
getContent: () => <TemplatesContent />,
},
avatars: {
label: 'Avatars',
icon: <Icon as={IconName.AVATAR} />,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/bundles/studio/constants/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export { MIN_SCENE_DURATION } from './min-scene-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';
export { TEMPLATE_SAVE_FAILED_NOTOFICATION_ID } from './template-save-failed-notification-id.js';
export { TEMPLATE_SAVE_NOTOFICATION_ID } from './template-save-notification-id.js';
export { VIDEO_SAVE_FAILED_NOTIFICATION_ID } from './video-save-failed-notification-id.js';
export { VIDEO_SAVE_NOTIFICATION_ID } from './video-save-notification-id.js';
export { VIDEO_SUBMIT_FAILED_NOTIFICATION_ID } from './video-submit-failed-id.constant.js';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const TEMPLATE_SAVE_FAILED_NOTOFICATION_ID = 'template-save-failed';

export { TEMPLATE_SAVE_FAILED_NOTOFICATION_ID };
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const TEMPLATE_SAVE_NOTOFICATION_ID = 'template-save';

export { TEMPLATE_SAVE_NOTOFICATION_ID };
2 changes: 1 addition & 1 deletion frontend/src/bundles/studio/enums/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export { NotificationMessage } from './notification-message.enum.js';
export { NotificationTitle } from './notification-title.enum.js';
export { PlayIconNames } from './play-icon-names.enum.js';
export { RowNames } from './row-names.enum.js';
export { AvatarsApiPath, SpeechApiPath } from 'shared';
export { AvatarsApiPath, SpeechApiPath, TemplateApiPath } from 'shared';
2 changes: 1 addition & 1 deletion frontend/src/bundles/studio/enums/menu-items.enum.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// TODO: Uncomment menu items after demo
const MenuItems = {
// TEMPLATES: 'templates',
TEMPLATES: 'templates',
AVATARS: 'avatars',
SCRIPT: 'script',
// TEXT: 'text',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ const NotificationMessage = {
'To create a video, you need to have an avatar and a script.',
VIDEO_SAVE: 'Video saved successfully',
VIDEO_SAVE_FAILED: 'Video save failed',
TEMPLATE_SAVE: 'Template saved successfully',
TEMPLATE_SAVE_FAILED: 'Template save failed',
} as const;

export { NotificationMessage };
2 changes: 2 additions & 0 deletions frontend/src/bundles/studio/enums/notification-title.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const NotificationTitle = {
SCRIPT_AND_AVATAR_ARE_REQUIRED: 'Script and avatar are required',
VIDEO_SAVED: 'Video saved',
VIDEO_SAVE_FAILED: 'Video save failed',
TEMPLATE_SAVED: 'Template saved',
TEMPLATE_SAVE_FAILED: 'Template save failed',
} as const;

export { NotificationTitle };
Loading

0 comments on commit 231d164

Please sign in to comment.