Стилизация формы создания лекции #12

Merged
alexredux merged 3 commits from feature/#11-styled-form-add-lesson into master 2024-03-31 11:44:45 +03:00
3 changed files with 334 additions and 87 deletions

View File

@ -51,11 +51,11 @@ export const api = createApi({
query: (courseId) => `/lesson/list/${courseId}`, query: (courseId) => `/lesson/list/${courseId}`,
providesTags: ['LessonList'] providesTags: ['LessonList']
}), }),
createLesson: builder.mutation<BaseResponse<Lesson>, Pick<Lesson, 'name'> & { courseId: string }>({ createLesson: builder.mutation<BaseResponse<Lesson>, Pick<Lesson, 'name' | 'date'> & { courseId: string }>({
query: ({ name, courseId }) => ({ query: ({ name, courseId, date }) => ({
url: '/lesson', url: '/lesson',
method: 'POST', method: 'POST',
body: { name, courseId }, body: { name, courseId, date },
}), }),
invalidatesTags: ['LessonList'] invalidatesTags: ['LessonList']
}), }),

View File

@ -2,34 +2,44 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { Link, useParams } from 'react-router-dom' import { Link, useParams } from 'react-router-dom'
import { getNavigationsValue } from '@ijl/cli' import { getNavigationsValue } from '@ijl/cli'
import { useForm, Controller } from 'react-hook-form'
import { import {

тут убери отступ. Библиотеки вместе

тут убери отступ. Библиотеки вместе

убрал отступ

убрал отступ
Breadcrumb, Breadcrumb,
BreadcrumbItem, BreadcrumbItem,
BreadcrumbLink, BreadcrumbLink,
Container,
Box,
Card,
CardBody,
CardHeader,
Heading,
Button,
ButtonGroup,
CloseButton,
useToast,
Stack,
VStack,
FormControl,
FormLabel,
FormHelperText,
FormErrorMessage,
Input,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { import { AddIcon } from '@chakra-ui/icons'
ArrowImg,
IconButton, import { LessonItem, Lessonname, ErrorSpan } from './style'
InputElement,
InputLabel,
InputWrapper,
StartWrapper,
LessonItem,
Lessonname,
Papper,
ErrorSpan,
Cross,
AddButton,
MainWrapper,
} from './style'
import arrow from '../assets/36-arrow-right.svg'
import { keycloak } from '../__data__/kc' import { keycloak } from '../__data__/kc'
import { useAppSelector } from '../__data__/store' import { useAppSelector } from '../__data__/store'
import { api } from '../__data__/api/api' import { api } from '../__data__/api/api'
import { isTeacher } from '../utils/user' import { isTeacher } from '../utils/user'
interface NewLessonForm {
name: string
date: string
}
const LessonList = () => { const LessonList = () => {
const { courseId } = useParams() const { courseId } = useParams()
const user = useAppSelector((s) => s.user) const user = useAppSelector((s) => s.user)
@ -37,6 +47,20 @@ const LessonList = () => {
const [createLesson, crLQuery] = api.useCreateLessonMutation() const [createLesson, crLQuery] = api.useCreateLessonMutation()
const [value, setValue] = useState('') const [value, setValue] = useState('')
const [showForm, setShowForm] = useState(false) const [showForm, setShowForm] = useState(false)
const {
control,
handleSubmit,
reset,
formState: { errors },
getValues,
} = useForm<NewLessonForm>({
defaultValues: {
name: '',
date: '',
},
})
const toast = useToast()
const toastRef = useRef(null)
const handleChange = useCallback( const handleChange = useCallback(
(event) => { (event) => {
@ -44,26 +68,38 @@ const LessonList = () => {
}, },
[setValue], [setValue],
) )
const handleSubmit = useCallback( const onSubmit = ({ name, date }) => {
(event) => { toastRef.current = toast({
event.preventDefault() title: 'Отправляем',
createLesson({ name: value, courseId }) status: 'loading',
}, duration: 9000,
[value], })
) createLesson({ name, courseId, date })
}
useEffect(() => { useEffect(() => {
if (crLQuery.isSuccess) { if (crLQuery.isSuccess) {
setValue('') const values = getValues()
if (toastRef.current) {
toast.update(toastRef.current, {
title: 'Лекция создана',
description: `Лекция ${values.name} успешно создана`,
status: 'success',
duration: 9000,
isClosable: true,
})
}
reset()
} }
}, [crLQuery.isSuccess]) }, [crLQuery.isSuccess])
return ( return (
<MainWrapper> <Container maxW="container.xl">
<StartWrapper>
<Breadcrumb> <Breadcrumb>
<BreadcrumbItem> <BreadcrumbItem>
<BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}>Журнал</BreadcrumbLink> <BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}>
Журнал
</BreadcrumbLink>
</BreadcrumbItem> </BreadcrumbItem>
<BreadcrumbItem isCurrentPage> <BreadcrumbItem isCurrentPage>
@ -72,37 +108,99 @@ const LessonList = () => {
</Breadcrumb> </Breadcrumb>
{isTeacher(user) && ( {isTeacher(user) && (
<> <Box mt="15" mb="15">
{showForm ? ( {showForm ? (
<Papper> <Card align="left">
<Cross role="button" onClick={() => setShowForm(false)}> <CardHeader display="flex">
X <Heading as="h2" mt="0">
</Cross> Создание лекции
<form onSubmit={handleSubmit}> </Heading>
<InputWrapper> <CloseButton ml="auto" onClick={() => setShowForm(false)} />
<InputLabel htmlFor="input"> </CardHeader>
Название новой лекции: <CardBody>
</InputLabel> <form onSubmit={handleSubmit(onSubmit)}>
<InputElement <VStack spacing="10" align="left">
value={value} <Controller
onChange={handleChange} control={control}
id="input" name="date"
type="text" rules={{ required: 'Обязательное поле' }}
autoComplete="off" render={({ field }) => (
<FormControl>
<FormLabel>Дата</FormLabel>
<Input
{...field}
required={false}
placeholder="Укажите дату лекции"
size="md"
type="datetime-local"
/> />
<IconButton type="submit"> {errors.date ? (
<ArrowImg src={arrow} /> <FormErrorMessage>
</IconButton> {errors.date?.message}
</InputWrapper> </FormErrorMessage>
) : (
<FormHelperText>
Укажите дату и время лекции
</FormHelperText>
)}
</FormControl>
)}
/>
<Controller
control={control}
name="name"
rules={{ required: 'Обязательное поле' }}
render={({ field }) => (
<FormControl
isRequired
isInvalid={Boolean(errors.name)}
>
<FormLabel>Название новой лекции:</FormLabel>
<Input
{...field}
required={false}
placeholder="Название лекции"
size="md"
/>
{errors.name && (
<FormErrorMessage>
{errors.name.message}
</FormErrorMessage>
)}
</FormControl>
)}
/>
<Box mt="10">
<Button
size="lg"
type="submit"
leftIcon={<AddIcon />}
colorScheme="blue"
>
Создать
</Button>
</Box>
</VStack>
{crLQuery.error && ( {crLQuery.error && (
<ErrorSpan>{(crLQuery.error as any).error}</ErrorSpan> <ErrorSpan>{(crLQuery.error as any).error}</ErrorSpan>
)} )}
</form> </form>
</Papper> </CardBody>
</Card>
) : ( ) : (
<AddButton onClick={() => setShowForm(true)}>Добавить</AddButton> <Box p="2" m="2">
<Button
leftIcon={<AddIcon />}
colorScheme="green"
onClick={() => setShowForm(true)}
>
Добавить
</Button>
</Box>
)} )}
</> </Box>
)} )}
<ul style={{ paddingLeft: 0 }}> <ul style={{ paddingLeft: 0 }}>
{data?.body?.map((lesson) => ( {data?.body?.map((lesson) => (
@ -124,8 +222,7 @@ const LessonList = () => {
</LessonItem> </LessonItem>
))} ))}
</ul> </ul>
</StartWrapper> </Container>
</MainWrapper>
) )
} }

View File

@ -592,6 +592,155 @@
"email": "sharova@mail.ru" "email": "sharova@mail.ru"
} }
],
"date": "2024-03-08T21:18:07.033Z",
"created": "2024-03-05T21:18:07.033Z",
"__v": 22
},
{
"_id": "65e78c0fced789d2f6791tt5",
"name": "ВВОДНАЯ ПО JS.ПРИМЕНЕНИЕ И СПОСОБЫ ПОДКЛЮЧЕНИЯ НА СТРАНИЦЕ. LET, CONST. БАЗОВЫЕ ТИПЫ ДАННЫХ, ПРИВЕДЕНИЕ ТИПОВ. ПЕРЕМЕННЫЕ, ОБЛАСТЬ ВИДИМОСТИ ПЕРЕМЕННЫХ",
"students": [
{
"sub": "fcde3f22-d9ba-412a-a572-c59e515a290f",
"email_verified": true,
"name": "Мария Капитанова",
"preferred_username": "maryaKapitan@gmail.com",
"given_name": "Мария",
"family_name": "Капитанова",
"email": "maryaKapitan@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJgIjjOFD2YUSyRF5kH4jaysE6X5p-kq0Cg0CFncfMi=s96-c"
},
{
"sub": "5b072deb-33ee-443e-9718-3b5720a3dfb7",
"email_verified": true,
"name": "Евгений Кореной",
"preferred_username": "koren@gmail.com",
"given_name": "Кореной",
"family_name": "Евгений",
"email": "koren@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJpVhDeG-Rpjjm2Un6r8ACz_s_injuIFKpzXf3qmyCn3Cg=s96-c"
},
{
"sub": "7adf0cd1-cf07-4079-88d8-1a5c9b8f42c2",
"email_verified": true,
"name": "Ирина Игнатьева",
"preferred_username": "irign@gmailcom",
"given_name": "Ирина",
"family_name": "Игнатьева",
"email": "irign@gmailcom",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocL45E4Gt8D5oyIl3ipkcGsv4ShWGs3bdlwEMA_1rzGZ=s96-c"
},
{
"sub": "95ccc005-95b9-4305-9447-364a32033911",
"email_verified": true,
"name": "Иван Петров",
"preferred_username": "petrov@mail.ru",
"given_name": "Иван",
"family_name": "Петров",
"email": "petrov@mail.ru",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocIgQn5mfDAh2djx-3ofG9z1Em26ZyuUgVPd-6rDOl6z=s96-c"
},
{
"sub": "ede1ef2c-6ecf-484a-8fb8-282a77e1caa1",
"email_verified": true,
"name": "Константин Тимуров",
"preferred_username": "konstantK@gmail.com",
"given_name": "Константин",
"family_name": "Тимуров",
"email": "konstantK@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJjnOfqaoAU_D4STrJPN9fPOeJ8tv60WbWVZu2ZWcHs=s96-c"
},
{
"sub": "92cc6a15-805c-4439-b592-b23f32d6d208",
"email_verified": true,
"name": "Александра Питерская",
"preferred_username": "piteralex@gmail.com",
"given_name": "Александра",
"family_name": "Питерская",
"email": "piteralex@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocKhbCbWvBBc_m7bjU5sLCE-dQ-KygBk-aUCSR8XaYtq=s96-c"
},
{
"sub": "4a3ba8b8-4120-4877-a160-be9ba4d5b3e3",
"email_verified": true,
"name": "Анастасия Светлых",
"preferred_username": "anastasya@gmail.ocm",
"given_name": "Анастасия",
"family_name": "Светлых",
"email": "anastasya@gmail.ocm",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJnsM8UGhbH806yLVgWZ17g3-gJFVcG0Uz5kvqT7dvC=s96-c"
},
{
"sub": "b4634921-00b3-4082-9284-8ac47f269394",
"email_verified": true,
"name": "Эмилия Снежко",
"preferred_username": "emi@mail.ru",
"given_name": "Эмилия",
"family_name": "Снежко",
"email": "emi@mail.ru",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocI98dzSFQDPr2LXMPFEUX8KLY6bY2m08O_aAj2B5KVNKg=s96-c"
},
{
"sub": "bf1a95aa-39a2-4528-9b8d-319409995df5",
"email_verified": true,
"name": "Юлия Бобова",
"preferred_username": "bobova@gmail.com",
"given_name": "Юлия",
"family_name": "Бобова",
"email": "bobova@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJ_Ud4iI-jgqcJ3QJcWpESbRLX_C1BnB8_7uTTC-4Dn=s96-c"
},
{
"sub": "c273a3e3-f7ba-4057-8c57-a1f43b6174a5",
"email_verified": true,
"name": "Анна Самоварова",
"preferred_username": "samovar@gmail.com",
"given_name": "Анна",
"family_name": "Самоварова",
"email": "samovar@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJOhIMdQkXPd55wTMgTTkUCnqbsu4EncgEPm67iz_mK=s96-c"
},
{
"sub": "8555885b-715c-4dee-a7c5-9563a6a05211",
"email_verified": true,
"name": "Евгения Жужова",
"preferred_username": "zhuzhova@gmail.com",
"given_name": "Евгения",
"family_name": "Жужова",
"email": "zhuzhova@gmail.com",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocJUtJBAVBm642AxoGpMDDMV8CPu3MEoLjU3hmO7oisG=s96-c"
},
{
"sub": "12dee54f-64e9-4be3-9cb0-02ff07ab24fe",
"email_verified": true,
"name": "Эдгар Петренко",
"preferred_username": "petrenk@mail.ru",
"given_name": "Эдгар",
"family_name": "Петренко",
"email": "petrenk@mail.ru",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocLgKAZag32kpGVHMVbh_GsU-rX_MAtmeVIPoov0ZPBYIA=s96-c"
},
{
"sub": "4082b72a-4730-4841-ad68-06a0e19263df",
"email_verified": true,
"name": "Елена Вавилон",
"preferred_username": "elenvavil@mail.ru",
"given_name": "Елена",
"family_name": "Вавилон",
"email": "elenvavil@mail.ru",
"picture": "https://lh3.googleusercontent.com/a/ACg8ocKXcmzcqRch2--j2Ge2m9e8MIOZ8y1MjsQ0cSEoXOmW=s96-c"
},
{
"sub": "9e8a08d8-d76a-4f26-99c5-9a1d3c067104",
"email_verified": true,
"name": "Ольга Шарова",
"preferred_username": "julyashap",
"given_name": "Ольга",
"family_name": "Шарова",
"email": "sharova@mail.ru"
}
], ],
"date": "2024-03-08T21:18:07.033Z", "date": "2024-03-08T21:18:07.033Z",
"created": "2024-03-05T21:18:07.033Z", "created": "2024-03-05T21:18:07.033Z",
@ -599,3 +748,4 @@
} }
] ]
} }