Skip to content

Commit

Permalink
Merge pull request #440 from BinaryStudioAcademy/task/OV-405-create-t…
Browse files Browse the repository at this point in the history
…emplates-page

OV-405: Create templates page
  • Loading branch information
nikita-remeslov authored Sep 27, 2024
2 parents e8df78a + b5d0509 commit ce9380e
Show file tree
Hide file tree
Showing 22 changed files with 471 additions and 5 deletions.
3 changes: 3 additions & 0 deletions frontend/src/bundles/common/components/button/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Properties = {
isDisabled?: boolean;
className?: string | undefined;
onClick?: () => void;
leftIcon?: React.ReactElement;
} & ChakraProperties;

const Button: React.FC<Properties> = ({
Expand All @@ -20,6 +21,7 @@ const Button: React.FC<Properties> = ({
size = 'md',
isDisabled = false,
className,
leftIcon,
onClick,
...ChakraProperties
}) => (
Expand All @@ -31,6 +33,7 @@ const Button: React.FC<Properties> = ({
isDisabled={isDisabled}
className={className}
onClick={onClick}
{...(leftIcon ? { leftIcon } : {})}
{...ChakraProperties}
>
{label}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/bundles/common/components/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export {
IconButton,
Image,
InputGroup,
InputLeftElement,
InputRightElement,
Button as LibraryButton,
Input as LibraryInput,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/bundles/common/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
import { useFormField } from '~/bundles/common/hooks/hooks.js';

type Properties<T extends FormValues> = {
label: string;
label?: string;
name: FieldInputProps<T>['name'];
type?: 'text' | 'email' | 'number' | 'password';
isRequired?: boolean;
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/bundles/common/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { useFormField } from '~/bundles/common/hooks/hooks.js';

type Properties<T extends FormValues> = {
label: string;
label?: string;
name: FieldInputProps<T>['name'];
children: React.ReactNode;
isRequired?: boolean;
Expand All @@ -31,7 +31,7 @@ const Select: React.FC<Properties<FormValues>> = ({

return (
<FormControl isInvalid={!isValid} isRequired={isRequired}>
<FormLabel htmlFor={name}>{label}</FormLabel>
{label && <FormLabel htmlFor={name}>{label}</FormLabel>}
<Field
{...field}
id={name}
Expand Down
14 changes: 14 additions & 0 deletions frontend/src/bundles/common/components/sidebar/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ const Sidebar: React.FC<Properties> = ({ children }) => {
label="My Avatar"
/>
</Link>
<Link to={AppRoute.TEMPLATES}>
<SidebarItem
bg={activeButtonPage(AppRoute.TEMPLATES)}
icon={
<Icon
as={IconName.TEMPLATE}
boxSize={5}
color={activeIconPage(AppRoute.TEMPLATES)}
/>
}
isCollapsed={isCollapsed}
label="Templates"
/>
</Link>
</Box>
<Spacer />
<SidebarItem
Expand Down
1 change: 1 addition & 0 deletions frontend/src/bundles/common/enums/app-route.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const AppRoute = {
MY_AVATAR: '/my-avatar',
ANY: '*',
CREATE_AVATAR: '/create-avatar',
TEMPLATES: '/templates',
} as const;

export { AppRoute };
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type Parameters<T extends FormValues = FormValues> = {
initialValues: T;
mode?: ValueOf<typeof ValidationMode>;
validationSchema?: ValidationSchema;
onSubmit: FormConfig<T>['onSubmit'];
onSubmit?: FormConfig<T>['onSubmit'];
};

type ReturnValue<T extends FormValues = FormValues> = ReturnType<
Expand All @@ -32,7 +32,9 @@ const useAppForm = <T extends FormValues = FormValues>({
initialValues,
mode = 'onSubmit',
validationSchema,
onSubmit,
onSubmit = (values: T): void => {
values;
},
}: Parameters<T>): ReturnValue<T> => {
const validateOnBlur =
mode === ValidationMode.ALL ? true : mode === ValidationMode.ON_BLUR;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
faForwardStep,
faHouse,
faImage,
faMagnifyingGlass,
faPause,
faPen,
faPlay,
Expand Down Expand Up @@ -47,6 +48,7 @@ const Stop = convertIcon(faStop);
const VideoCamera = convertIcon(faVideoCamera);
const Image = convertIcon(faImage);
const Circle = convertIcon(faCircle);
const Magnifying = convertIcon(faMagnifyingGlass);

export {
BackwardStep,
Expand All @@ -60,6 +62,7 @@ export {
ForwardStep,
House,
Image,
Magnifying,
Pause,
Pen,
Play,
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/bundles/common/icons/icon-name.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
ForwardStep,
House,
Image,
Magnifying,
Pause,
Pen,
Play,
Expand Down Expand Up @@ -77,6 +78,7 @@ const IconName = {
IMAGE: Image,
CIRCLE: Circle,
ARROW_BACK: ArrowBackIcon,
MAGNIFYING: Magnifying,
} as const;

export { IconName };
2 changes: 2 additions & 0 deletions frontend/src/bundles/template/components/components.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { CreationsSection } from './creations-section/creations-section.js';
export { TemplatesSection } from './templates-section/templates-section.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import {
Box,
Button,
Flex,
Heading,
} from '~/bundles/common/components/components.js';
import { Circles, Dots } from '~/bundles/my-avatar/components/components.js';
import { type Template } from '~/bundles/template/types/types.js';

import { TemplateCard } from '../template-card/template-card.js';
import styles from './styles.module.css';

//TODO: Change with the backend information
const templates: Template[] = [];

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

const CreationsSection: React.FC<Properties> = ({ onClick }) => {
return (
<Box padding="17px 0">
<Flex alignItems="center" marginBottom="9px">
<Heading color="typography.900" variant="H3" marginRight="11px">
Recent Creations
</Heading>
</Flex>

{templates.length > 0 ? (
<Box className={styles['horizontal']}>
{templates.map(({ id, ...template }) => (
<Box
key={id}
flex="0 0 auto"
marginRight="20px"
width="250px"
>
<TemplateCard {...template} />
</Box>
))}
</Box>
) : (
<Flex
bg="white"
h="140px"
borderRadius="lg"
justify="center"
align="center"
overflow="hidden"
maxWidth="340px"
>
<Box w={{ base: '222px', sm: '222px' }} position="relative">
<Circles />
<Dots />
<Button
label="Create Your First Template"
variant="outlined"
onClick={onClick}
/>
</Box>
</Flex>
)}
</Box>
);
};

export { CreationsSection };
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.horizontal {
display: flex;
overflow-x: auto;
scrollbar-width: thin;
scrollbar-color: #c1c1c1 #f1f1f1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.play-button {
position: absolute;
background-color: white;
top: 5px;
right: 5px;
}

.preview-image {
border-radius: 5px;
height: 100%;
width: 100%;
object-fit: cover;
object-position: top;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import {
Badge,
Box,
Icon,
IconButton,
Image,
Text,
} from '~/bundles/common/components/components.js';
import { useCallback, useState } from '~/bundles/common/hooks/hooks.js';
import { IconName } from '~/bundles/common/icons/icons.js';
import { PlayerModal } from '~/bundles/home/components/player-modal/player-modal.js';
import { DeleteWarning } from '~/bundles/home/components/video-card/components/delete-warning.js';

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

type Properties = {
name: string;
url: string | null;
previewUrl: string;
};

const TemplateCard: React.FC<Properties> = ({ name, url, previewUrl }) => {
const [isVideoModalOpen, setIsVideoModalOpen] = useState(false);
const [isWarningModalOpen, setIsWarningModalOpen] = useState(false);

const handleIconClick = useCallback(() => {
if (url) {
return setIsVideoModalOpen(true);
}
}, [url]);

const handleVideoModalClose = useCallback(() => {
setIsVideoModalOpen(false);
}, []);

const handleWarningModalClose = useCallback(() => {
setIsWarningModalOpen(false);
}, []);

const handleDelete = useCallback(() => {
handleWarningModalClose();
}, [handleWarningModalClose]);

return (
<Box borderRadius="8px" bg="white" padding="7px">
<Box
position="relative"
role="group"
height="115px"
overflow="hidden"
>
<Image
src={previewUrl}
alt="Video preview"
className={styles['preview-image']}
/>

<IconButton
size="xs"
aria-label={url ? 'Play video' : 'Edit video'}
_groupHover={{ opacity: 1 }}
onClick={handleIconClick}
className={styles['play-button']}
icon={
<Icon
as={url ? IconName.PLAY : IconName.PEN}
color="background.600"
/>
}
/>
</Box>

<Box padding="7px 10px 5px 5px">
<Text variant="button" color="typography.900">
{name}
</Text>
</Box>

<Badge
color="typography.900"
textTransform="none"
bg="background.300"
fontWeight="400"
padding="0 8px"
borderRadius="24px"
>
Advertisement
</Badge>

{url && (
<PlayerModal
videoUrl={url}
isOpen={isVideoModalOpen}
onClose={handleVideoModalClose}
/>
)}

<DeleteWarning
isOpen={isWarningModalOpen}
onClose={handleWarningModalClose}
onDelete={handleDelete}
/>
</Box>
);
};

export { TemplateCard };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const DEFAULT_TEMPLATE_PAYLOAD = {
category: '',
search: '',
format: '',
};

export { DEFAULT_TEMPLATE_PAYLOAD };
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.button {
width: 100%;
border-radius: 20px;
background-color: #f6f5fa;
color: #6b6b6b;
}

.button.selected {
background-color: white;
color: #4a4a4a;
}
Loading

0 comments on commit ce9380e

Please sign in to comment.