mirror of
https://github.com/sergeyyarkov/educt-client.git
synced 2026-10-11 10:19:22 +03:00
feat: create course page layout
This commit is contained in:
parent
b2541ff3e5
commit
3799f150a8
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
62
src/pages/courses/create/components/CreateCourseForm.tsx
Normal file
62
src/pages/courses/create/components/CreateCourseForm.tsx
Normal 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;
|
||||||
3
src/pages/courses/create/components/index.ts
Normal file
3
src/pages/courses/create/components/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import CreateCourseForm from './CreateCourseForm';
|
||||||
|
|
||||||
|
export default CreateCourseForm;
|
||||||
@ -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 mt='6'>
|
||||||
|
<CreateCourseForm />
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -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} {user.last_name}
|
{user.fullname}
|
||||||
</Link>
|
</Link>
|
||||||
<Text fontSize='sm'>{user.email}</Text>
|
<Text fontSize='sm'>{user.email}</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@ -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
10
src/types/index.d.ts
vendored
@ -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 = {
|
||||||
|
|||||||
@ -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: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user