mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
189 lines
5.8 KiB
TypeScript
189 lines
5.8 KiB
TypeScript
import React, { useEffect, useState } from 'react';
|
|
import {
|
|
FormControl,
|
|
FormHelperText,
|
|
FormLabel,
|
|
Text,
|
|
Input,
|
|
InputGroup,
|
|
Stack,
|
|
Box,
|
|
Button,
|
|
Textarea,
|
|
Flex,
|
|
Divider,
|
|
} from '@chakra-ui/react';
|
|
import * as constants from '@educt/constants';
|
|
import { Controller, UseFormReturn } from 'react-hook-form';
|
|
import VideoUploader from '@educt/components/VideoUploader';
|
|
import FilesUploader from '@educt/components/FilesUploader';
|
|
import { FileSupportedFormatsEnum, VideoSupportedFormatsEnum } from '@educt/enums';
|
|
import type { AttachmentFileType, LessonVideoType } from '@educt/types';
|
|
import { DESCRIPTION_MAX_LENGTH } from './LessonForm.validator';
|
|
|
|
export type InputFields = {
|
|
title: string;
|
|
description: string;
|
|
duration: string;
|
|
video: File;
|
|
linked_video_url?: string | undefined;
|
|
materials?: FileList | undefined;
|
|
};
|
|
|
|
export type LessonFormPropsType = {
|
|
onSubmit: () => Promise<void>;
|
|
buttonLabel: string;
|
|
isLoading: boolean;
|
|
reactHookForm: UseFormReturn<InputFields>;
|
|
preloadedVideo?: LessonVideoType | undefined;
|
|
preloadedMaterials?: AttachmentFileType[] | undefined;
|
|
};
|
|
|
|
const LessonForm: React.FC<LessonFormPropsType> = ({
|
|
onSubmit,
|
|
buttonLabel,
|
|
isLoading,
|
|
reactHookForm,
|
|
preloadedVideo,
|
|
preloadedMaterials,
|
|
}) => {
|
|
const {
|
|
control,
|
|
register,
|
|
watch,
|
|
formState: { errors, isDirty },
|
|
unregister,
|
|
} = reactHookForm;
|
|
|
|
const [isLinkedVideoUrl, setIsLinkedVideoUrl] = useState<boolean>(false);
|
|
|
|
const watchDescription = watch('description');
|
|
|
|
useEffect(() => {
|
|
if (!isLinkedVideoUrl) {
|
|
unregister('linked_video_url');
|
|
}
|
|
}, [isLinkedVideoUrl]);
|
|
|
|
return (
|
|
<form onSubmit={onSubmit}>
|
|
<Stack spacing={'5'}>
|
|
<FormControl isRequired id='title' isInvalid={!!errors.title}>
|
|
<FormLabel>Title</FormLabel>
|
|
<InputGroup>
|
|
<Input placeholder='Lesson name' type='text' {...register('title')} />
|
|
</InputGroup>
|
|
<Text as='small' color='red.500'>
|
|
{errors.title?.message}
|
|
</Text>
|
|
<FormHelperText>e.g Introduction</FormHelperText>
|
|
</FormControl>
|
|
|
|
<FormControl isRequired id='description' isInvalid={!!errors.description}>
|
|
<FormLabel>Description</FormLabel>
|
|
<Textarea resize='none' minH='150px' placeholder='Lesson description...' {...register('description')} />
|
|
<Flex justifyContent='space-between'>
|
|
<Text as='small' color='red.500'>
|
|
{errors.description?.message}
|
|
</Text>
|
|
<Text
|
|
as='small'
|
|
color={!!errors.description || watchDescription?.length > DESCRIPTION_MAX_LENGTH ? 'red.500' : 'gray.500'}
|
|
>
|
|
{watchDescription?.length || 0}/{DESCRIPTION_MAX_LENGTH}
|
|
</Text>
|
|
</Flex>
|
|
</FormControl>
|
|
|
|
{isLinkedVideoUrl ? (
|
|
<FormControl id='linked_video_url'>
|
|
<FormLabel>Video URL</FormLabel>
|
|
<Input placeholder='Link to video source. (YouTube, Vimeo, .mp4)' {...register('linked_video_url')} />
|
|
<Text as='small' color='red.500'>
|
|
{errors.linked_video_url?.message}
|
|
</Text>
|
|
<FormHelperText textDecoration={'underline'} cursor='pointer' onClick={() => setIsLinkedVideoUrl(false)}>
|
|
choose from files
|
|
</FormHelperText>
|
|
</FormControl>
|
|
) : (
|
|
<FormControl id='video'>
|
|
<FormLabel>Video</FormLabel>
|
|
<Controller
|
|
control={control}
|
|
name='video'
|
|
render={({ field: { onChange, value: file } }) => (
|
|
<VideoUploader
|
|
onChange={file => onChange(file)}
|
|
file={file}
|
|
setIsLinkedVideoUrl={setIsLinkedVideoUrl}
|
|
preloadedVideoUrl={preloadedVideo && constants.BACKEND_URL + preloadedVideo.url}
|
|
/>
|
|
)}
|
|
/>
|
|
<Text as='small' color='red.500'>
|
|
{errors.video?.message}
|
|
</Text>
|
|
<FormHelperText>
|
|
Supported formats:{' '}
|
|
{Object.keys(VideoSupportedFormatsEnum)
|
|
.map(ext => `${ext.toLowerCase()}`)
|
|
.join(', ')}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
)}
|
|
|
|
<FormControl isRequired id='duration'>
|
|
<FormLabel>Video duration</FormLabel>
|
|
<Input type='time' defaultValue={'00:30:00'} step='1' {...register('duration')} />
|
|
<Text as='small' color='red.500'>
|
|
{errors.duration?.message}
|
|
</Text>
|
|
<FormHelperText>hours:minutes:seconds</FormHelperText>
|
|
</FormControl>
|
|
|
|
<FormControl>
|
|
<FormLabel>Materials</FormLabel>
|
|
<Controller
|
|
control={control}
|
|
name='materials'
|
|
render={({ field: { onChange, value: files } }) => (
|
|
<FilesUploader
|
|
onChange={files => onChange(files)}
|
|
files={Array.from(files || [])}
|
|
preloadedFiles={preloadedMaterials}
|
|
/>
|
|
)}
|
|
/>
|
|
<Text as='small' color='red.500'>
|
|
{errors.materials?.message}
|
|
</Text>
|
|
<FormHelperText>
|
|
Supported formats:{' '}
|
|
{Object.keys(FileSupportedFormatsEnum)
|
|
.map(ext => `${ext.toLowerCase()}`)
|
|
.join(', ')}
|
|
</FormHelperText>
|
|
</FormControl>
|
|
|
|
<Divider />
|
|
|
|
<Box mt='5'>
|
|
<Button
|
|
isLoading={isLoading}
|
|
isDisabled={!isDirty}
|
|
loadingText='Saving...'
|
|
type='submit'
|
|
colorScheme='blue'
|
|
variant='outline'
|
|
>
|
|
{buttonLabel}
|
|
</Button>
|
|
</Box>
|
|
</Stack>
|
|
</form>
|
|
);
|
|
};
|
|
|
|
export default LessonForm;
|