mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 18:29:15 +03:00
fix: update course image
This commit is contained in:
parent
aa351d1c15
commit
44e8fa3158
@ -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} />;
|
||||||
|
|||||||
@ -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>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -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'>
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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 => {
|
||||||
setState(s => ({ ...s, data: data.data }));
|
if (isMountedRef.current) {
|
||||||
|
setState(s => ({ ...s, data: data.data }));
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
setState(s => ({ ...s, error }));
|
if (isMountedRef.current) {
|
||||||
|
setState(s => ({ ...s, error }));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setState(s => ({ ...s, loading: false, fetched: true }));
|
if (isMountedRef.current) {
|
||||||
|
setState(s => ({ ...s, loading: false, fetched: true }));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, [id]);
|
}, [id]);
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user