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