mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
refactor: creating page layout
This commit is contained in:
parent
2bcaad519e
commit
cd2af7eae1
@ -1,5 +1,5 @@
|
||||
import { UserRoleEnum } from '@educt/enums';
|
||||
import { MdAccountCircle, MdCollectionsBookmark, MdGroup, MdHome, MdMessage } from 'react-icons/md';
|
||||
import { MdAccountCircle, MdCollectionsBookmark, MdGroup, MdHome, MdMessage, MdList } from 'react-icons/md';
|
||||
import { IAppConfig } from './interfaces';
|
||||
import packageJson from '../package.json';
|
||||
|
||||
@ -18,6 +18,13 @@ const config: IAppConfig = {
|
||||
links: [
|
||||
{ location: '/', title: 'Main', public: true, icon: MdHome },
|
||||
{ location: '/courses', title: 'Courses', public: true, icon: MdCollectionsBookmark },
|
||||
{
|
||||
location: '/lessons',
|
||||
title: 'Lessons',
|
||||
public: false,
|
||||
icon: MdList,
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.TEACHER],
|
||||
},
|
||||
{ location: '/messages', title: 'Messages', public: true, icon: MdMessage },
|
||||
{ location: '/profile', title: 'Profile', public: true, icon: MdAccountCircle },
|
||||
{
|
||||
|
||||
@ -5,7 +5,6 @@ import { Box, Grid, Text } from '@chakra-ui/react';
|
||||
/**
|
||||
* Types
|
||||
*/
|
||||
import { ICourse } from '@educt/interfaces';
|
||||
import { CourseStatusEnum } from '@educt/enums';
|
||||
import { CourseItemPropsType } from './CourseItem';
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
useToast,
|
||||
Text,
|
||||
Flex,
|
||||
Stack,
|
||||
Button,
|
||||
Textarea,
|
||||
FormControl,
|
||||
@ -12,8 +13,9 @@ import {
|
||||
InputGroup,
|
||||
InputRightElement,
|
||||
Input,
|
||||
FormHelperText,
|
||||
Divider,
|
||||
} from '@chakra-ui/react';
|
||||
import { MdCloudUpload } from 'react-icons/md';
|
||||
import { SubmitHandler, useForm, useWatch, Controller } from 'react-hook-form';
|
||||
import { yupResolver } from '@hookform/resolvers/yup';
|
||||
import AsyncSelect from '@educt/components/AsyncSelect';
|
||||
@ -150,11 +152,11 @@ const CreateCourseForm: React.FC<CreateCourseFormPropsType> = () => {
|
||||
return (
|
||||
<Box>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<Grid templateColumns={{ md: '2.5fr 1fr' }} gap='5'>
|
||||
<Stack spacing='5'>
|
||||
<FormControl isRequired id='title' isInvalid={!!errors.title}>
|
||||
<FormLabel>Title</FormLabel>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<InputGroup>
|
||||
<Input pr='60px' size='md' placeholder='Type course title' type='text' {...register('title')} />
|
||||
<Input pr='60px' size='md' placeholder='Course name' type='text' {...register('title')} />
|
||||
<InputRightElement
|
||||
mr='2'
|
||||
children={
|
||||
@ -164,26 +166,24 @@ const CreateCourseForm: React.FC<CreateCourseFormPropsType> = () => {
|
||||
}
|
||||
/>
|
||||
</InputGroup>
|
||||
<FormHelperText>e.g Web Development in Javascript</FormHelperText>
|
||||
<Text as='small' color='red.500'>
|
||||
{errors.title?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
|
||||
<FormControl id='image' isInvalid={!!errors.image}>
|
||||
<FormLabel>Image</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
name='image'
|
||||
render={({ field: { onChange } }) => (
|
||||
<FileSelect onChange={file => onChange(file)} supportedFormats={['JPG', 'JPEG', 'PNG', 'WEBP']} />
|
||||
)}
|
||||
/>
|
||||
<FormControl isRequired id='description' isInvalid={!!errors.description}>
|
||||
<FormLabel>Description</FormLabel>
|
||||
<Textarea resize='none' minH='150px' placeholder='Course description...' {...register('description')} />
|
||||
<Text as='small' color='red.500'>
|
||||
{errors.image?.message}
|
||||
{errors.description?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
|
||||
<FormControl isRequired id='category_id' gridColumn='1' isInvalid={!!errors.category_id}>
|
||||
<Flex justifyContent='space-between' flexDirection={{ base: 'column', lg: 'row' }}>
|
||||
<Box flexGrow={1} flexBasis='0' mr={{ base: '0', lg: '7' }}>
|
||||
<Stack spacing='5'>
|
||||
<FormControl isRequired id='category_id' isInvalid={!!errors.category_id}>
|
||||
<FormLabel>Category</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
@ -204,14 +204,8 @@ const CreateCourseForm: React.FC<CreateCourseFormPropsType> = () => {
|
||||
</Text>
|
||||
</FormControl>
|
||||
|
||||
<FormControl
|
||||
isRequired
|
||||
id='teacher_id'
|
||||
gridColumn={{ md: '2' }}
|
||||
gridRow={{ md: '1' }}
|
||||
isInvalid={!!errors.teacher_id}
|
||||
>
|
||||
<FormLabel>Teacher</FormLabel>
|
||||
<FormControl isRequired id='teacher_id' isInvalid={!!errors.teacher_id}>
|
||||
<FormLabel>Author</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
name='teacher_id'
|
||||
@ -220,7 +214,7 @@ const CreateCourseForm: React.FC<CreateCourseFormPropsType> = () => {
|
||||
loadOptions={loadUsersOptions}
|
||||
onChange={selected => onChange(selected)}
|
||||
value={value}
|
||||
placeholder='Select Teacher'
|
||||
placeholder='Select Author'
|
||||
noOptionsMessage='There are no teachers.'
|
||||
loadingText='Wait...'
|
||||
/>
|
||||
@ -230,41 +224,40 @@ const CreateCourseForm: React.FC<CreateCourseFormPropsType> = () => {
|
||||
{errors.teacher_id?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
</Stack>
|
||||
</Box>
|
||||
|
||||
<FormControl isRequired id='description' gridColumn='1' isInvalid={!!errors.description}>
|
||||
<FormLabel>Description</FormLabel>
|
||||
<Textarea
|
||||
resize='none'
|
||||
minH='150px'
|
||||
placeholder='Write some description for course...'
|
||||
{...register('description')}
|
||||
<Box flexGrow={0} flexBasis='50%' mt={{ base: '5', lg: '0' }}>
|
||||
<FormControl id='image' isInvalid={!!errors.image}>
|
||||
<FormLabel>Image</FormLabel>
|
||||
<Controller
|
||||
control={control}
|
||||
name='image'
|
||||
render={({ field: { onChange } }) => (
|
||||
<FileSelect onChange={file => onChange(file)} supportedFormats={['JPG', 'JPEG', 'PNG', 'WEBP']} />
|
||||
)}
|
||||
/>
|
||||
<Text as='small' color='red.500'>
|
||||
{errors.description?.message}
|
||||
{errors.image?.message}
|
||||
</Text>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Flex mt='6'>
|
||||
</Box>
|
||||
</Flex>
|
||||
</Stack>
|
||||
|
||||
<Divider mt='5' />
|
||||
|
||||
<Box mt='5'>
|
||||
<Button
|
||||
isLoading={isLoading}
|
||||
loadingText='Saving...'
|
||||
type='submit'
|
||||
mr='2'
|
||||
colorScheme='blue'
|
||||
variant='outline'
|
||||
rightIcon={<MdCloudUpload size='14px' />}
|
||||
onClick={() => setStatus(CourseStatusEnum.DRAFT)}
|
||||
>
|
||||
Save as Draft
|
||||
</Button>
|
||||
<Button
|
||||
loadingText='Saving...'
|
||||
type='submit'
|
||||
colorScheme='green'
|
||||
onClick={() => setStatus(CourseStatusEnum.PUBLISHED)}
|
||||
>
|
||||
Publish
|
||||
Create
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
</form>
|
||||
</Box>
|
||||
);
|
||||
|
||||
@ -17,15 +17,15 @@ import CreateCourseForm from './components';
|
||||
*/
|
||||
const CreateCoursePage: React.FC<IPageProps> = () => {
|
||||
return (
|
||||
<Box maxW='1200px'>
|
||||
<Box>
|
||||
<Box>
|
||||
<Flex alignItems='center'>
|
||||
<PrevPageButton prevPage='/courses' />
|
||||
<Heading as='h1'>Create course</Heading>
|
||||
<Heading as='h1'>Course creation</Heading>
|
||||
</Flex>
|
||||
<Text mt='3'>Fill in the required fields to create a course</Text>
|
||||
</Box>
|
||||
<Box mt='6'>
|
||||
<Box mt='5'>
|
||||
<CreateCourseForm />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
18
src/pages/lessons/lessons.tsx
Normal file
18
src/pages/lessons/lessons.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import { Box, Heading, Text } from '@chakra-ui/react';
|
||||
|
||||
import { IPageProps } from '@educt/interfaces';
|
||||
|
||||
/**
|
||||
* Lessons page
|
||||
*/
|
||||
const LessonsPage: React.FC<IPageProps> = () => {
|
||||
return (
|
||||
<Box>
|
||||
<Heading as='h1'>Lessons page</Heading>
|
||||
<Text mt='2'>List of all created lessons in the system.</Text>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default LessonsPage;
|
||||
@ -37,7 +37,7 @@ const UsersPage: React.FC<IPageProps> = () => {
|
||||
|
||||
return (
|
||||
<UsersPageContextProvider>
|
||||
<Box h='100%'>
|
||||
<Box>
|
||||
<Heading as='h1'>User management</Heading>
|
||||
<Text mt='2'>You can add or delete users on this page.</Text>
|
||||
<Flex mt='5' flexDir='column' h='full'>
|
||||
|
||||
@ -11,6 +11,7 @@ import ChangePasswordPage from '@educt/pages/profile/change-password/change-pass
|
||||
import ChangeEmailPage from '@educt/pages/profile/change-email/change-email';
|
||||
import { UserRoleEnum } from './enums';
|
||||
const CoursesPage = lazy(() => import('@educt/pages/courses/courses'));
|
||||
const LessonsPage = lazy(() => import('@educt/pages/lessons/lessons'));
|
||||
const MainPage = lazy(() => import('@educt/pages/main/main'));
|
||||
const MessagesPage = lazy(() => import('@educt/pages/messages/messages'));
|
||||
const ProfilePage = lazy(() => import('@educt/pages/profile/profile'));
|
||||
@ -40,6 +41,15 @@ export const routes: IRouteOption[] = [
|
||||
title: 'Create new course',
|
||||
component: CreateCoursePage,
|
||||
isPrivate: true,
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.TEACHER],
|
||||
},
|
||||
{
|
||||
path: '/lessons',
|
||||
title: 'Lessons',
|
||||
component: LessonsPage,
|
||||
isPrivate: true,
|
||||
exact: true,
|
||||
roles: [UserRoleEnum.ADMIN, UserRoleEnum.TEACHER],
|
||||
},
|
||||
{
|
||||
path: '/messages',
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user