import React, { useEffect, useMemo, useRef, useState, } from 'react' import dayjs from 'dayjs' import { Link, useParams } from 'react-router-dom' import { getNavigationsValue, getFeatures } from '@brojs/cli' import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, Container, Box, Button, useToast, Toast, TableContainer, Table, Thead, Tr, Th, Tbody, Td, Menu, MenuButton, MenuItem, Text, MenuList, AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, } from '@chakra-ui/react' import { AddIcon, EditIcon } from '@chakra-ui/icons' import { useAppSelector } from '../../__data__/store' import { api } from '../../__data__/api/api' import { isTeacher } from '../../utils/user' import { qrCode } from '../../assets' import { Lesson } from '../../__data__/model' import { XlSpinner } from '../../components/xl-spinner' import { LessonForm } from './components/lessons-form' import { BreadcrumbsWrapper } from './style' import { Bar } from './components/bar' const features = getFeatures('journal') const barFeature = features?.['lesson.bar'] const groupByDate = features?.['group.by.date'] const LessonList = () => { const { courseId } = useParams() const user = useAppSelector((s) => s.user) const { data, isLoading, error, isSuccess } = api.useLessonListQuery(courseId) const [createLesson, crLQuery] = api.useCreateLessonMutation() const [deleteLesson, deletingRqst] = api.useDeleteLessonMutation() const [updateLesson, updateLessonRqst] = api.useUpdateLessonMutation() const [showForm, setShowForm] = useState(false) const [lessonToDelete, setlessonToDelete] = useState<Lesson>(null) const cancelRef = React.useRef() const toast = useToast() const toastRef = useRef(null) const createdLessonRef = useRef(null) const [editLesson, setEditLesson] = useState<Lesson>(null) const sorted = useMemo(() => [...(data?.body || [])]?.sort((a, b) => a.date > b.date ? 1 : -1), [data, data?.body]) const lessonCalc = useMemo(() => { if (!isSuccess) { return [] } if (!groupByDate) { return [{ date: '', data: sorted }] } const lessonsData = [] for (let i = 0; i < sorted.length; i++) { const element = sorted[i] const find = lessonsData.find( (item) => dayjs(element.date).diff(dayjs(item.date), 'day') === 0, ) if (find) { find.data.push(element) } else { lessonsData.push({ date: element.date, data: [element], }) } } return lessonsData.sort((a, b) => a.date < b.date? 1 : -1) }, [groupByDate, isSuccess, sorted]) const onSubmit = (lessonData) => { toastRef.current = toast({ title: 'Отправляем', status: 'loading', duration: 9000, }) createdLessonRef.current = lessonData if (editLesson) updateLesson(lessonData) else createLesson({ courseId, ...lessonData }) } useEffect(() => { if (deletingRqst.isError) { toast({ title: (deletingRqst.error as any)?.error, status: 'error', duration: 3000, }) } if (deletingRqst.isSuccess) { const lesson = { ...lessonToDelete } toast({ status: 'warning', duration: 9000, render: ({ id, ...toastProps }) => ( <Toast {...toastProps} id={id} title={ <> <Box pb={3}> <Text fontSize="xl">{`Удалена лекция ${lesson.name}`}</Text> </Box> <Button onClick={() => { createLesson({ courseId, ...lesson }) toast.close(id) }} > Восстановить </Button> </> } /> ), }) setlessonToDelete(null) } }, [deletingRqst.isLoading, deletingRqst.isSuccess, deletingRqst.isError]) useEffect(() => { if (crLQuery.isSuccess) { const toastProps = { title: 'Лекция создана', description: `Лекция ${createdLessonRef.current.name} успешно создана`, status: 'success' as 'success', duration: 9000, isClosable: true, } if (toastRef.current) toast.update(toastRef.current, toastProps) else toast(toastProps) setShowForm(false) } }, [crLQuery.isSuccess]) useEffect(() => { if (updateLessonRqst.isSuccess) { const toastProps = { title: 'Лекция Обновлена', description: `Лекция ${createdLessonRef.current.name} успешно обновлена`, status: 'success' as 'success', duration: 9000, isClosable: true, } if (toastRef.current) toast.update(toastRef.current, toastProps) else toast(toastProps) setShowForm(false) } }, [updateLessonRqst.isSuccess]) if (isLoading) { return <XlSpinner />; } return ( <> <AlertDialog isOpen={Boolean(lessonToDelete)} leastDestructiveRef={cancelRef} onClose={() => setlessonToDelete(null)} > <AlertDialogOverlay> <AlertDialogContent> <AlertDialogHeader fontSize="lg" fontWeight="bold"> Удалить занятие от{' '} {dayjs(lessonToDelete?.date).format('DD.MM.YY')}? </AlertDialogHeader> <AlertDialogBody> Все данные о посещении данного занятия будут удалены </AlertDialogBody> <AlertDialogFooter> <Button isDisabled={deletingRqst.isLoading} ref={cancelRef} onClick={() => setlessonToDelete(null)} > Cancel </Button> <Button colorScheme="red" loadingText="" isLoading={deletingRqst.isLoading} onClick={() => deleteLesson(lessonToDelete._id)} ml={3} > Delete </Button> </AlertDialogFooter> </AlertDialogContent> </AlertDialogOverlay> </AlertDialog> <BreadcrumbsWrapper> <Breadcrumb> <BreadcrumbItem> <BreadcrumbLink as={Link} to={getNavigationsValue('journal.main')}> Журнал </BreadcrumbLink> </BreadcrumbItem> <BreadcrumbItem isCurrentPage> <BreadcrumbLink href="#">Курс</BreadcrumbLink> </BreadcrumbItem> </Breadcrumb> </BreadcrumbsWrapper> <Container maxW="container.xl" position="relative"> {isTeacher(user) && ( <Box mt="15" mb="15"> {showForm ? ( <LessonForm key={editLesson?._id} isLoading={crLQuery.isLoading} onSubmit={onSubmit} onCancel={() => { setShowForm(false) setEditLesson(null) }} error={(crLQuery.error as any)?.error} lesson={editLesson} title={editLesson ? 'Редактирование лекции' : 'Создание лекции'} nameButton={editLesson ? 'Редактировать' : 'Создать'} /> ) : ( <Box p="2" m="2"> <Button leftIcon={<AddIcon />} colorScheme="green" onClick={() => setShowForm(true)} > Добавить </Button> </Box> )} </Box> )} {barFeature && sorted?.length && ( <Box height="300"> <Bar data={sorted.map((lesson, index) => ({ lessonIndex: `#${index + 1}`, count: lesson.students.length, }))} /> </Box> )} <TableContainer whiteSpace="wrap" pb={13}> <Table variant="striped" colorScheme="cyan"> <Thead> <Tr> {isTeacher(user) && ( <Th align="center" width={1}> ссылка </Th> )} <Th textAlign="center" width={1}> Дата </Th> <Th>Название</Th> {isTeacher(user) && <Th>action</Th>} <Th isNumeric>Отмечено</Th> </Tr> </Thead> <Tbody> {lessonCalc?.map(({ data: lessons, date }) => ( <React.Fragment key={date}> {date && <Tr><Td colSpan={isTeacher(user) ? 5 : 3}>{dayjs(date).format('DD MMMM YYYY')}</Td></Tr>} {lessons.map((lesson) => ( <Tr key={lesson._id}> {isTeacher(user) && ( <Td> <Link to={`${getNavigationsValue('journal.main')}/lesson/${courseId}/${lesson._id}`} style={{ display: 'flex' }} > <img width={24} src={qrCode} style={{ margin: '0 auto' }} /> </Link> </Td> )} <Td textAlign="center"> {dayjs(lesson.date).format(groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')} </Td> <Td>{lesson.name}</Td> {isTeacher(user) && ( <Td> <Menu> <MenuButton as={Button}> <EditIcon /> </MenuButton> <MenuList> <MenuItem onClick={() => { setShowForm(true) setEditLesson(lesson) }} > Edit </MenuItem> <MenuItem onClick={() => setlessonToDelete(lesson)} > Delete </MenuItem> </MenuList> </Menu> </Td> )} <Td isNumeric>{lesson.students.length}</Td> </Tr> ))} </React.Fragment> ))} </Tbody> </Table> </TableContainer> </Container> </> ) } export default LessonList