fix: update course image

This commit is contained in:
Sergey Yarkov 2021-11-14 20:05:29 +03:00
parent aa351d1c15
commit 44e8fa3158
6 changed files with 43 additions and 16 deletions

View File

@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
import Select from '@educt/components/Select'; import Select from '@educt/components/Select';
import { ISelectPropsType } from '../Select/Select'; import { ISelectPropsType } from '../Select/Select';
import { OptionType } from '@educt/types'; import { OptionType } from '@educt/types';
import useIsMountedRef from '@educt/hooks/useIsMountedRef';
interface IAsyncSelectPropsType extends ISelectPropsType { interface IAsyncSelectPropsType extends ISelectPropsType {
loadOptions: () => Promise<OptionType[] | undefined>; loadOptions: () => Promise<OptionType[] | undefined>;
@ -10,13 +11,22 @@ interface IAsyncSelectPropsType extends ISelectPropsType {
const AsyncSelect: React.FC<IAsyncSelectPropsType> = props => { const AsyncSelect: React.FC<IAsyncSelectPropsType> = props => {
const [options, setOptions] = useState<OptionType[] | []>([]); const [options, setOptions] = useState<OptionType[] | []>([]);
const [isLoading, setIsLoading] = useState<boolean>(false); const [isLoading, setIsLoading] = useState<boolean>(false);
const isMountedRef = useIsMountedRef();
const { loadOptions, ...selectProps } = props; const { loadOptions, ...selectProps } = props;
useEffect(() => { useEffect(() => {
setIsLoading(true); if (isMountedRef.current) setIsLoading(true);
loadOptions() loadOptions()
.then(options => options && setOptions(options)) .then(options => {
.finally(() => setIsLoading(false)); if (options && isMountedRef.current) {
setOptions(options);
}
})
.finally(() => {
if (isMountedRef.current) {
setIsLoading(false);
}
});
}, []); }, []);
return <Select options={options} isLoading={isLoading} {...selectProps} />; return <Select options={options} isLoading={isLoading} {...selectProps} />;

View File

@ -1,4 +1,4 @@
import React, { useState, useRef } from 'react'; import React, { useRef } from 'react';
import { Flex, Box, Text } from '@chakra-ui/layout'; import { Flex, Box, Text } from '@chakra-ui/layout';
import { Input } from '@chakra-ui/input'; import { Input } from '@chakra-ui/input';
import { Button } from '@chakra-ui/button'; import { Button } from '@chakra-ui/button';
@ -13,10 +13,10 @@ import { useColorModeValue } from '@chakra-ui/color-mode';
type FileSelectPropsType = { type FileSelectPropsType = {
onChange: (file: File) => void; onChange: (file: File) => void;
supportedFormats?: string[]; supportedFormats?: string[];
file?: File | undefined;
}; };
const FileSelect: React.FC<FileSelectPropsType> = ({ onChange, supportedFormats }) => { const FileSelect: React.FC<FileSelectPropsType> = ({ onChange, file, supportedFormats }) => {
const [selectedFile, setSelectedFile] = useState<File | undefined>(undefined);
const fileInputRef = useRef<HTMLInputElement>(null); const fileInputRef = useRef<HTMLInputElement>(null);
/** /**
@ -37,7 +37,6 @@ const FileSelect: React.FC<FileSelectPropsType> = ({ onChange, supportedFormats
const file = files[0]; const file = files[0];
onChange(file); onChange(file);
setSelectedFile(file);
} }
}; };
@ -52,12 +51,12 @@ const FileSelect: React.FC<FileSelectPropsType> = ({ onChange, supportedFormats
<Input type='file' ref={fileInputRef} onChange={onChangeFileHandler} display='none' /> <Input type='file' ref={fileInputRef} onChange={onChangeFileHandler} display='none' />
<Flex justifyContent='space-between' alignItems='center' sx={{ gap: '10px' }}> <Flex justifyContent='space-between' alignItems='center' sx={{ gap: '10px' }}>
<Box> <Box>
{selectedFile ? ( {file ? (
<Text fontSize='lg' fontWeight='bold'> <Text fontSize='lg' fontWeight='bold'>
{selectedFile.name} {file.name}
<br /> <br />
<Text as='small' fontWeight='normal'> <Text as='small' fontWeight='normal'>
{helpres.transformBytes(selectedFile.size)} {helpres.transformBytes(file.size)}
</Text> </Text>
</Text> </Text>
) : ( ) : (

View File

@ -177,8 +177,12 @@ const CourseForm: React.FC<CourseFormPropsType> = ({ onSubmit, buttonLabel, isLo
<Controller <Controller
control={control} control={control}
name='image' name='image'
render={({ field: { onChange } }) => ( render={({ field: { onChange, value: file } }) => (
<FileSelect onChange={file => onChange(file)} supportedFormats={['JPG', 'JPEG', 'PNG', 'WEBP']} /> <FileSelect
onChange={file => onChange(file)}
file={file}
supportedFormats={['JPG', 'JPEG', 'PNG', 'WEBP']}
/>
)} )}
/> />
<Text as='small' color='red.500'> <Text as='small' color='red.500'>

View File

@ -70,6 +70,7 @@ const EditFormCourse: React.FC<EditFormCoursePropsType> = ({ defaultValues }) =>
description: data.description, description: data.description,
teacher_id: data.teacher_id, teacher_id: data.teacher_id,
category_id: data.category_id, category_id: data.category_id,
image: data.image,
}); });
toast({ title: `Course updated.`, status: 'info' }); toast({ title: `Course updated.`, status: 'info' });
@ -81,6 +82,7 @@ const EditFormCourse: React.FC<EditFormCoursePropsType> = ({ defaultValues }) =>
description: course.data.description, description: course.data.description,
teacher_id: course.data.teacher.id, teacher_id: course.data.teacher.id,
category_id: course.data.category.id, category_id: course.data.category.id,
image: undefined,
}); });
} catch (error: any) { } catch (error: any) {
if (error.response) { if (error.response) {

View File

@ -5,6 +5,7 @@ import { ICourse } from '@educt/interfaces';
*/ */
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useErrorHandler } from 'react-error-boundary'; import { useErrorHandler } from 'react-error-boundary';
import useIsMountedRef from './useIsMountedRef';
import { useRootStore } from './useRootStore'; import { useRootStore } from './useRootStore';
type CourseStateType = { type CourseStateType = {
@ -19,6 +20,7 @@ const useFetchCourseQuery = (id: string) => {
courseStore: { courseService }, courseStore: { courseService },
} = useRootStore(); } = useRootStore();
const [state, setState] = useState<CourseStateType>({ data: null, error: null, loading: false, fetched: false }); const [state, setState] = useState<CourseStateType>({ data: null, error: null, loading: false, fetched: false });
const isMountedRef = useIsMountedRef();
const handleError = useErrorHandler(); const handleError = useErrorHandler();
/** /**
@ -29,17 +31,23 @@ const useFetchCourseQuery = (id: string) => {
courseService courseService
.fetchById(id) .fetchById(id)
.then(data => { .then(data => {
if (isMountedRef.current) {
setState(s => ({ ...s, data: data.data })); setState(s => ({ ...s, data: data.data }));
}
}) })
.catch(error => { .catch(error => {
if (error.response) { if (error.response) {
if (isMountedRef.current) {
setState(s => ({ ...s, error })); setState(s => ({ ...s, error }));
}
} else { } else {
handleError(error); handleError(error);
} }
}) })
.finally(() => { .finally(() => {
if (isMountedRef.current) {
setState(s => ({ ...s, loading: false, fetched: true })); setState(s => ({ ...s, loading: false, fetched: true }));
}
}); });
}, [id]); }, [id]);

View File

@ -76,7 +76,11 @@ export class CourseService {
id: string, id: string,
data: UpdateCourseParamsType data: UpdateCourseParamsType
): Promise<IApiRespose<Omit<ICourse, 'students_count' | 'likes_count' | 'lessons_count'>>> { ): Promise<IApiRespose<Omit<ICourse, 'students_count' | 'likes_count' | 'lessons_count'>>> {
const result = await this.api.patch(`/v1/courses/${id}`, data); const result = await this.api.patch(`/v1/courses/${id}`, helpers.transformToFormData(data), {
headers: {
'Content-Type': 'multipart/form-data',
},
});
return result.data; return result.data;
} }