CRUD лекции #17

Merged
primakov merged 2 commits from feature/edit-delete-lesson into master 2024-04-01 23:25:14 +03:00
5 changed files with 227 additions and 163 deletions
Showing only changes of commit c68cea7fa6 - Show all commits

2
.gitignore vendored
View File

@ -9,6 +9,8 @@ pids
*.pid *.pid
*.seed *.seed
*prom.json
# Directory for instrumented libs generated by jscoverage/JSCover # Directory for instrumented libs generated by jscoverage/JSCover
lib-cov lib-cov

View File

@ -35,6 +35,7 @@ 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'
import { AddIcon, ArrowDownIcon, ArrowUpIcon, LinkIcon } from '@chakra-ui/icons' import { AddIcon, ArrowDownIcon, ArrowUpIcon, LinkIcon } from '@chakra-ui/icons'
import { Course } from '../__data__/model'
interface NewCourseForm { interface NewCourseForm {
startDt: string startDt: string
@ -226,7 +227,15 @@ const CoursesList = () => {
) )
} }
const CourseCard = ({ course, isOpened, openDetails }) => { const CourseCard = ({
course,
isOpened,
openDetails,
}: {
course: Course
isOpened: boolean
openDetails: () => void
}) => {
const [getLessonList, lessonList] = api.useLazyLessonListQuery() const [getLessonList, lessonList] = api.useLazyLessonListQuery()
useEffect(() => { useEffect(() => {
if (isOpened) { if (isOpened) {
@ -262,6 +271,7 @@ const CourseCard = ({ course, isOpened, openDetails }) => {
{lessonList.data?.body?.map((lesson) => ( {lessonList.data?.body?.map((lesson) => (
<Link <Link
as={ConnectedLink} as={ConnectedLink}
key={lesson._id}
to={ to={
isTeacher(user) isTeacher(user)
? `${getNavigationsValue('journal.main')}/lesson/${course._id}/${lesson._id}` ? `${getNavigationsValue('journal.main')}/lesson/${course._id}/${lesson._id}`

View File

@ -20,6 +20,7 @@ import {
Lessonname, Lessonname,
AddMissedButton, AddMissedButton,
UnorderList, UnorderList,
BreadcrumbsWrapper,
} from './style' } from './style'
import { api } from '../__data__/api/api' import { api } from '../__data__/api/api'
import { User } from '../__data__/model' import { User } from '../__data__/model'
@ -86,8 +87,8 @@ const LessonDetail = () => {
}, [accessCode?.body, AllStudents.data]) }, [accessCode?.body, AllStudents.data])
return ( return (
<Container maxW="container.xl" centerContent px="200"> <>
<VStack align="left"> <BreadcrumbsWrapper>
<Breadcrumb> <Breadcrumb>
<BreadcrumbItem> <BreadcrumbItem>
<BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}> <BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}>
@ -108,41 +109,45 @@ const LessonDetail = () => {
<BreadcrumbLink href="#">Лекция</BreadcrumbLink> <BreadcrumbLink href="#">Лекция</BreadcrumbLink>
</BreadcrumbItem> </BreadcrumbItem>
</Breadcrumb> </Breadcrumb>
<Heading as='h3' mt='4' mb='3'> </BreadcrumbsWrapper>
Тема занятия: <Container maxW="container.xl" centerContent px="200">
</Heading> <VStack align="left">
<Box as="span"> <Heading as="h3" mt="4" mb="3">
{accessCode?.body?.lesson?.name} Тема занятия:
</Box> </Heading>
<Box as='span'> <Box as="span">{accessCode?.body?.lesson?.name}</Box>
{dayjs(accessCode?.body?.lesson?.date).format('DD MMMM YYYYг.')}{' '} <Box as="span">
Отмечено - {accessCode?.body?.lesson?.students?.length}{' '} {dayjs(accessCode?.body?.lesson?.date).format('DD MMMM YYYYг.')}{' '}
{AllStudents.isSuccess ? `/ ${AllStudents?.data?.body?.length}` : ''}{' '} Отмечено - {accessCode?.body?.lesson?.students?.length}{' '}
человек {AllStudents.isSuccess
</Box> ? `/ ${AllStudents?.data?.body?.length}`
</VStack> : ''}{' '}
<HStack spacing="8"> человек
<a href={userUrl}> </Box>
<QRCanvas ref={canvRef} /> </VStack>
</a> <HStack spacing="8">
<UnorderList> <a href={userUrl}>
{studentsArr.map((student) => ( <QRCanvas ref={canvRef} />
<LessonItem key={student.sub} warn={!student.present}> </a>
<Lessonname> <UnorderList>
{student.name || student.preferred_username}{' '} {studentsArr.map((student) => (
{!student.present && ( <LessonItem key={student.sub} warn={!student.present}>
<AddMissedButton <Lessonname>
onClick={() => manualAdd({ lessonId, user: student })} {student.name || student.preferred_username}{' '}
> {!student.present && (
add <AddMissedButton
</AddMissedButton> onClick={() => manualAdd({ lessonId, user: student })}
)} >
</Lessonname> add
</LessonItem> </AddMissedButton>
))} )}
</UnorderList> </Lessonname>
</HStack> </LessonItem>
</Container> ))}
</UnorderList>
</HStack>
</Container>
</>
) )
} }

View File

@ -24,16 +24,24 @@ import {
FormHelperText, FormHelperText,
FormErrorMessage, FormErrorMessage,
Input, Input,
TableContainer,
Table,
Thead,
Tr,
Th,
Tbody,
Td,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { AddIcon } from '@chakra-ui/icons' import { AddIcon } from '@chakra-ui/icons'
import { LessonItem, Lessonname, ErrorSpan } from './style' import { LessonItem, Lessonname, ErrorSpan, BreadcrumbsWrapper } from './style'
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'
import { qrCode } from '../assets'
interface NewLessonForm { interface NewLessonForm {
name: string name: string
@ -94,135 +102,171 @@ const LessonList = () => {
}, [crLQuery.isSuccess]) }, [crLQuery.isSuccess])
return ( return (
<Container maxW="container.xl"> <>
<Breadcrumb> <BreadcrumbsWrapper>
<BreadcrumbItem> <Breadcrumb>
<BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}> <BreadcrumbItem>
Журнал <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>
</BreadcrumbsWrapper>
<Container maxW="container.xl">
{isTeacher(user) && (
<Box mt="15" mb="15">
{showForm ? (
<Card align="left">
<CardHeader display="flex">
<Heading as="h2" mt="0">
Создание лекции
</Heading>
<CloseButton ml="auto" onClick={() => setShowForm(false)} />
</CardHeader>
<CardBody>
<form onSubmit={handleSubmit(onSubmit)}>
<VStack spacing="10" align="left">
<Controller
control={control}
name="date"
rules={{ required: 'Обязательное поле' }}
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>
)}
/>
{isTeacher(user) && ( <Controller
<Box mt="15" mb="15"> control={control}
{showForm ? ( name="name"
<Card align="left"> rules={{ required: 'Обязательное поле' }}
<CardHeader display="flex"> render={({ field }) => (
<Heading as="h2" mt="0"> <FormControl
Создание лекции isRequired
</Heading> isInvalid={Boolean(errors.name)}
<CloseButton ml="auto" onClick={() => setShowForm(false)} /> >
</CardHeader> <FormLabel>Название новой лекции:</FormLabel>
<CardBody> <Input
<form onSubmit={handleSubmit(onSubmit)}> {...field}
<VStack spacing="10" align="left"> required={false}
<Controller placeholder="Название лекции"
control={control} size="md"
name="date" />
rules={{ required: 'Обязательное поле' }} {errors.name && (
render={({ field }) => ( <FormErrorMessage>
<FormControl> {errors.name.message}
<FormLabel>Дата</FormLabel> </FormErrorMessage>
<Input )}
{...field} </FormControl>
required={false} )}
placeholder="Укажите дату лекции" />
size="md" <Box mt="10">
type="datetime-local" <Button
/> size="lg"
{errors.date ? ( type="submit"
<FormErrorMessage> leftIcon={<AddIcon />}
{errors.date?.message} colorScheme="blue"
</FormErrorMessage>
) : (
<FormHelperText>
Укажите дату и время лекции
</FormHelperText>
)}
</FormControl>
)}
/>
<Controller
control={control}
name="name"
rules={{ required: 'Обязательное поле' }}
render={({ field }) => (
<FormControl
isRequired
isInvalid={Boolean(errors.name)}
> >
<FormLabel>Название новой лекции:</FormLabel> Создать
<Input </Button>
{...field} </Box>
required={false} </VStack>
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>
</CardBody> </CardBody>
</Card> </Card>
) : ( ) : (
<Box p="2" m="2"> <Box p="2" m="2">
<Button <Button
leftIcon={<AddIcon />} leftIcon={<AddIcon />}
colorScheme="green" colorScheme="green"
onClick={() => setShowForm(true)} onClick={() => setShowForm(true)}
>
Добавить
</Button>
</Box>
)}
</Box>
)}
<TableContainer whiteSpace="wrap">
<Table variant="striped" colorScheme="cyan">
<Thead>
<Tr>
<Th align="center">ссылка</Th>
<Th>Дата</Th>
<Th>into</Th>
<Th isNumeric>Участников</Th>
</Tr>
</Thead>
<Tbody>
{data?.body?.map((lesson) => (
<Tr key={lesson._id}>
<Td>
<Link
to={
isTeacher(user)
? `${getNavigationsValue('journal.main')}/lesson/${courseId}/${lesson._id}`
: ''
}
style={{ display: 'flex' }}
>
<img width={24} src={qrCode} />
</Link>
</Td>
<Td>{dayjs(lesson.date).format('H:mm DD.MM.YY')}</Td>
<Td>{lesson.name}</Td>
<Td isNumeric>{lesson.students.length}</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
{/* <ul style={{ paddingLeft: 0 }}>
{data?.body?.map((lesson) => (
<LessonItem key={lesson._id}>
<Link
to={
isTeacher(user)
? `${getNavigationsValue('journal.main')}/lesson/${courseId}/${lesson._id}`
: ''
}
style={{ display: 'flex' }}
> >
Добавить <Lessonname>{lesson.name}</Lessonname>
</Button> <span>{dayjs(lesson.date).format('DD MMMM YYYYг.')}</span>
</Box> <span style={{ marginLeft: 'auto' }}>
)} Участников - {lesson.students.length}
</Box> </span>
)} </Link>
<ul style={{ paddingLeft: 0 }}> </LessonItem>
{data?.body?.map((lesson) => ( ))}
<LessonItem key={lesson._id}> </ul> */}
<Link </Container>
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

@ -4,6 +4,9 @@ import {
Card Card
} from '@chakra-ui/react' } from '@chakra-ui/react'
export const BreadcrumbsWrapper = styled.div`
padding: 12px;
`;
export const MainWrapper = styled.main` export const MainWrapper = styled.main`
display: flex; display: flex;