Стилизация формы создания лекции #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,88 +68,161 @@ 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 as={Link} to={getNavigationsValue('journal.main')}>Журнал</BreadcrumbLink> Журнал
</BreadcrumbItem> </BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbItem isCurrentPage> <BreadcrumbItem isCurrentPage>
<BreadcrumbLink href="#">Курс</BreadcrumbLink> <BreadcrumbLink href="#">Курс</BreadcrumbLink>
</BreadcrumbItem> </BreadcrumbItem>
</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"
/>
{errors.date ? (
<FormErrorMessage>
{errors.date?.message}
</FormErrorMessage>
) : (
<FormHelperText>
Укажите дату и время лекции
</FormHelperText>
)}
</FormControl>
)}
/> />
<IconButton type="submit">
<ArrowImg src={arrow} /> <Controller
</IconButton> control={control}
</InputWrapper> 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 />}
<ul style={{ paddingLeft: 0 }}> colorScheme="green"
{data?.body?.map((lesson) => ( onClick={() => setShowForm(true)}
<LessonItem key={lesson._id}>
<Link
to={
isTeacher(user)
? `${getNavigationsValue('journal.main')}/lesson/${courseId}/${lesson._id}`
: ''
}
style={{ display: 'flex' }}
> >
<Lessonname>{lesson.name}</Lessonname> Добавить
<span>{dayjs(lesson.date).format('DD MMMM YYYYг.')}</span> </Button>
<span style={{ marginLeft: 'auto' }}> </Box>
Участников - {lesson.students.length} )}
</span> </Box>
</Link> )}
</LessonItem> <ul style={{ paddingLeft: 0 }}>
))} {data?.body?.map((lesson) => (
</ul> <LessonItem key={lesson._id}>
</StartWrapper> <Link
</MainWrapper> to={
isTeacher(user)
? `${getNavigationsValue('journal.main')}/lesson/${courseId}/${lesson._id}`
: ''
}
style={{ display: 'flex' }}
>
<Lessonname>{lesson.name}</Lessonname>
<span>{dayjs(lesson.date).format('DD MMMM YYYYг.')}</span>
<span style={{ marginLeft: 'auto' }}>
Участников - {lesson.students.length}
</span>
</Link>
</LessonItem>
))}
</ul>
</Container>
) )
} }

View File

@ -592,10 +592,160 @@
"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",
"__v": 22 "__v": 22
} }
] ]
} }