feat: create course page layout

This commit is contained in:
Sergey Yarkov 2021-10-25 22:19:27 +03:00
parent b2541ff3e5
commit 3799f150a8
9 changed files with 91 additions and 21 deletions

View File

@ -1,5 +1,5 @@
import type { RouteComponentProps } from 'react-router-dom'; import type { RouteComponentProps } from 'react-router-dom';
import { CourseImage, LinkType } from '@educt/types'; import { AttachmentFileType, LinkType } from '@educt/types';
import { CourseStatusEnum, UserRoleEnum } from '../enums'; import { CourseStatusEnum, UserRoleEnum } from '../enums';
export interface IAppConfig { export interface IAppConfig {
@ -18,10 +18,10 @@ export interface IToken {
export interface ICourse { export interface ICourse {
id: string; id: string;
image: AttachmentFileType | null;
title: string; title: string;
description: string; description: string;
status: CourseStatusEnum; status: CourseStatusEnum;
image: null | CourseImage;
teacher: Pick<IUser, 'id' | 'first_name' | 'last_name' | 'email'>; teacher: Pick<IUser, 'id' | 'first_name' | 'last_name' | 'email'>;
category: ICategory; category: ICategory;
lessons: ILesson[]; lessons: ILesson[];
@ -81,6 +81,7 @@ export interface IUser {
id: string; id: string;
first_name: string; first_name: string;
last_name: string; last_name: string;
fullname: string;
email: string; email: string;
roles: IUserRole[]; roles: IUserRole[];
contacts: IUserContacts | null; contacts: IUserContacts | null;
@ -90,7 +91,6 @@ export interface IUser {
* Current authenticated user data * Current authenticated user data
*/ */
export interface IMe extends IUser { export interface IMe extends IUser {
fullname: string;
/** /**
* The field can be undefined if the user * The field can be undefined if the user
* does not have the STUDENT role * does not have the STUDENT role

View File

@ -111,7 +111,7 @@ const CourseItem: React.FC<CourseItemPropsType> = ({ course, onDelete, onSetStat
borderTopRightRadius='lg' borderTopRightRadius='lg'
p='10px' p='10px'
> >
{course.image && ( {course.image && course.image.url && (
<Image <Image
position='absolute' position='absolute'
top='0' top='0'
@ -123,7 +123,7 @@ const CourseItem: React.FC<CourseItemPropsType> = ({ course, onDelete, onSetStat
w='100%' w='100%'
borderTopLeftRadius='lg' borderTopLeftRadius='lg'
borderTopRightRadius='lg' borderTopRightRadius='lg'
src={`/api/assets/images/courses/${course.image.name}`} src={course.image.url}
/> />
)} )}
</Box> </Box>

View File

@ -0,0 +1,62 @@
import React from 'react';
import { Box, Grid } from '@chakra-ui/react';
import { Input } from '@chakra-ui/react';
import { Select, Flex, Button, Textarea } from '@chakra-ui/react';
import { FormControl, FormLabel, InputGroup, InputRightElement } from '@chakra-ui/react';
/**
* Types
*/
import { MdCloudUpload } from 'react-icons/md';
type CreateCourseFormProps = {};
const CreateCourseForm: React.FC<CreateCourseFormProps> = () => {
return (
<Box>
<form>
<Grid templateColumns={{ md: '2.5fr 1fr' }} gap='5'>
<FormControl id='title'>
<FormLabel>Title</FormLabel>
<InputGroup>
<Input size='md' placeholder='Type course title' type='text' />
<InputRightElement fontSize='sm' mr='2' color='gray.500' children={'0/60'} />
</InputGroup>
</FormControl>
<FormControl id='image'>
<FormLabel>Image</FormLabel>
<Input size='md' variant='unstyled' type='file' />
</FormControl>
<FormControl id='category' gridColumn='1'>
<FormLabel>Category</FormLabel>
<Select size='md' placeholder='Select category'>
<option value='option1'>Option 1</option>
<option value='option2'>Option 2</option>
<option value='option3'>Option 3</option>
</Select>
</FormControl>
<FormControl id='title' gridColumn={{ md: '2' }} gridRow={{ md: '1' }}>
<FormLabel>Teacher</FormLabel>
<Button w='full'>Select Teacher</Button>
</FormControl>
<FormControl id='description' gridColumn='1'>
<FormLabel>Description</FormLabel>
<Textarea resize='none' minH='150px' placeholder='Write some description for course...' />
</FormControl>
</Grid>
<Flex mt='6'>
<Button mr='2' colorScheme='blue' variant='outline' rightIcon={<MdCloudUpload size='14px' />}>
Save as Draft
</Button>
<Button colorScheme='green'>Publish</Button>
</Flex>
</form>
</Box>
);
};
export default CreateCourseForm;

View File

@ -0,0 +1,3 @@
import CreateCourseForm from './CreateCourseForm';
export default CreateCourseForm;

View File

@ -5,21 +5,22 @@ import { Box, Heading, Text } from '@chakra-ui/react';
* Types * Types
*/ */
import { IPageProps } from '@educt/interfaces'; import { IPageProps } from '@educt/interfaces';
import { observer } from 'mobx-react-lite'; import CreateCourseForm from './components';
/** /**
* Create course page * Create course page
*/ */
const CreateCoursePage: React.FC<IPageProps> = ({ title }) => { const CreateCoursePage: React.FC<IPageProps> = ({ title }) => {
return ( return (
<> <Box maxW='1200px'>
<Box> <Box>
<Box> <Heading as='h1'>Create course</Heading>
<Heading as='h1'>Create</Heading> <Text mt='2'>Fill in the required fields to create a course</Text>
<Text mt='2'>Create new course in the system.</Text>
</Box>
</Box> </Box>
</> <Box mt='6'>
<CreateCourseForm />
</Box>
</Box>
); );
}; };

View File

@ -49,10 +49,10 @@ const UserItem: React.FC<UserItemPropsType> = ({ user, onEdit, onDelete }) => {
<Box borderWidth='1px' borderRadius='lg' w='full' p='3'> <Box borderWidth='1px' borderRadius='lg' w='full' p='3'>
<Flex alignItems='center' justifyContent='space-between' sx={{ gap: '20px' }}> <Flex alignItems='center' justifyContent='space-between' sx={{ gap: '20px' }}>
<Flex alignItems='center' flexBasis='230px'> <Flex alignItems='center' flexBasis='230px'>
<Avatar name={`${user.first_name} ${user.last_name}`} size='sm' mr='3' /> <Avatar name={user.fullname} size='sm' mr='3' />
<Box> <Box>
<Link as={ReactRouterLink} to={`/user/${user.id}`} fontSize='md' fontWeight='medium'> <Link as={ReactRouterLink} to={`/user/${user.id}`} fontSize='md' fontWeight='medium'>
{user.first_name}&nbsp;{user.last_name} {user.fullname}
</Link> </Link>
<Text fontSize='sm'>{user.email}</Text> <Text fontSize='sm'>{user.email}</Text>
</Box> </Box>

View File

@ -55,17 +55,17 @@ export default class UserStore {
try { try {
const result = await this.userService.fetchMe(); const result = await this.userService.fetchMe();
const { const {
data: { id, first_name, last_name, email, roles, contacts, courses }, data: { id, first_name, last_name, fullname, email, roles, contacts, courses },
} = result; } = result;
runInAction(() => { runInAction(() => {
this.me = { this.me = {
id, id,
fullname: `${first_name} ${last_name}`,
first_name, first_name,
last_name, last_name,
email, email,
roles, roles,
fullname,
contacts, contacts,
courses, courses,
isAdmin: helpers.userContainRoles(roles, [UserRoleEnum.ADMIN]), isAdmin: helpers.userContainRoles(roles, [UserRoleEnum.ADMIN]),

10
src/types/index.d.ts vendored
View File

@ -15,12 +15,12 @@ export type LinkType = {
icon: IconType; icon: IconType;
}; };
export type CourseImage = { export type AttachmentFileType = {
id: number; url?: string;
size: number;
name: string; name: string;
ext: string; mimeType: string;
created_at: string; extname: string;
updated_at: string;
}; };
export type ConfirmEmailContainerDataType = { export type ConfirmEmailContainerDataType = {

View File

@ -25,6 +25,10 @@ export default defineConfig({
target: constants.BACKEND_URL, target: constants.BACKEND_URL,
changeOrigin: true, changeOrigin: true,
}, },
'/uploads': {
target: constants.BACKEND_URL,
changeOrigin: true,
},
}, },
}, },
resolve: { resolve: {