inline edit mode

This commit is contained in:
Primakov Alexandr Alexandrovich 2024-10-30 14:28:42 +03:00
parent 6b903b4d54
commit 3dfd854a4c
5 changed files with 327 additions and 183 deletions

View File

@ -1,3 +1,4 @@
/* eslint-disable react/display-name */
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom/client'; import ReactDOM from 'react-dom/client';

View File

@ -0,0 +1,144 @@
import React, { useEffect, useRef, useState } from 'react'
import dayjs from 'dayjs'
import { Link } from 'react-router-dom'
import { getNavigationsValue, getFeatures } from '@brojs/cli'
import {
Button,
Tr,
Td,
Menu,
MenuButton,
MenuItem,
MenuList,
useToast,
} from '@chakra-ui/react'
import { EditIcon } from '@chakra-ui/icons'
import { qrCode } from '../../../assets'
import { LessonForm } from './lessons-form'
import { api } from '../../../__data__/api/api'
const features = getFeatures('journal')
const groupByDate = features?.['group.by.date']
type ItemProps = {
id: string
date: string
name: string
isTeacher: boolean
courseId: string
setlessonToDelete(): void
students: unknown[]
}
export const Item: React.FC<ItemProps> = ({
id,
date,
name,
isTeacher,
courseId,
setlessonToDelete,
students,
}) => {
const [edit, setEdit] = useState(false)
const toastRef = useRef(null)
const toast = useToast()
const [updateLesson, updateLessonRqst] = api.useUpdateLessonMutation()
const createdLessonRef = useRef(null)
const onSubmit = (lessonData) => {
toastRef.current = toast({
title: 'Отправляем',
status: 'loading',
duration: 9000,
})
createdLessonRef.current = lessonData
if (navigator.onLine) {
updateLesson(lessonData)
} else {
toast.update(toastRef.current, {
title: 'Отсутствует интернет',
status: 'error',
duration: 3000
})
}
}
useEffect(() => {
if (updateLessonRqst.isSuccess) {
const toastProps = {
title: 'Лекция Обновлена',
description: `Лекция ${createdLessonRef.current?.name} успешно обновлена`,
status: 'success' as const,
duration: 9000,
isClosable: true,
}
if (toastRef.current) toast.update(toastRef.current, toastProps)
else toast(toastProps)
setEdit(false)
}
}, [updateLessonRqst.isSuccess])
if (edit && isTeacher) {
return (
<Tr>
<Td colSpan={5}>
<LessonForm
isLoading={updateLessonRqst.isLoading}
error={(updateLessonRqst.error as any)?.error}
onSubmit={onSubmit}
onCancel={() => {
setEdit(false)
}}
lesson={{ id, name, date }}
title={'Редактирование лекции'}
nameButton={'Сохранить'}
/>
</Td>
</Tr>
)
}
return (
<Tr>
{isTeacher && (
<Td>
<Link
to={`${getNavigationsValue('journal.main')}/lesson/${courseId}/${id}`}
style={{ display: 'flex' }}
>
<img width={24} src={qrCode} style={{ margin: '0 auto' }} />
</Link>
</Td>
)}
<Td textAlign="center">
{dayjs(date).format(groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')}
</Td>
<Td>{name}</Td>
{isTeacher && (
<Td>
{!edit && (
<Menu>
<MenuButton as={Button}>
<EditIcon />
</MenuButton>
<MenuList>
<MenuItem
onClick={() => {
setEdit(true)
}}
>
Edit
</MenuItem>
<MenuItem onClick={setlessonToDelete}>Delete</MenuItem>
</MenuList>
</Menu>
)}
{edit && <Button onClick={setlessonToDelete}>Сохранить</Button>}
</Td>
)}
<Td isNumeric>{students.length}</Td>
</Tr>
)
}

View File

@ -0,0 +1,45 @@
import React from 'react'
import dayjs from 'dayjs'
import {
Tr,
Td,
} from '@chakra-ui/react'
import { Lesson } from '../../../__data__/model'
import { Item } from './item'
type LessonItemProps = {
date: string
lessons: Lesson[]
isTeacher: boolean
courseId: string
setlessonToDelete(lesson: Lesson): void
}
export const LessonItems: React.FC<LessonItemProps> = ({
date,
lessons,
isTeacher,
courseId,
setlessonToDelete,
}) => (
<>
{date && (
<Tr>
<Td colSpan={isTeacher ? 5 : 3}>
{dayjs(date).format('DD MMMM YYYY')}
</Td>
</Tr>
)}
{lessons.map((lesson) => (
<Item
key={lesson.id}
{...lesson}
setlessonToDelete={() => setlessonToDelete(lesson)}
courseId={courseId}
isTeacher={isTeacher}
/>
))}
</>
)

View File

@ -22,8 +22,8 @@ import { Lesson } from '../../../__data__/model'
import { ErrorSpan } from '../style' import { ErrorSpan } from '../style'
interface NewLessonForm { interface NewLessonForm {
name: string; name: string
date: string; date: string
} }
interface LessonFormProps { interface LessonFormProps {
@ -51,7 +51,10 @@ export const LessonForm = ({
reset, reset,
formState: { errors }, formState: { errors },
} = useForm<NewLessonForm>({ } = useForm<NewLessonForm>({
defaultValues: (lesson && { ...lesson, date: dateToCalendarFormat(lesson.date) }) || { defaultValues: (lesson && {
...lesson,
date: dateToCalendarFormat(lesson.date),
}) || {
name: '', name: '',
date: dateToCalendarFormat(), date: dateToCalendarFormat(),
}, },

View File

@ -1,9 +1,4 @@
import React, { import React, { useEffect, useMemo, useRef, useState } from 'react'
useEffect,
useMemo,
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, getFeatures } from '@brojs/cli' import { getNavigationsValue, getFeatures } from '@brojs/cli'
@ -22,12 +17,7 @@ import {
Tr, Tr,
Th, Th,
Tbody, Tbody,
Td,
Menu,
MenuButton,
MenuItem,
Text, Text,
MenuList,
AlertDialog, AlertDialog,
AlertDialogBody, AlertDialogBody,
AlertDialogContent, AlertDialogContent,
@ -35,18 +25,18 @@ import {
AlertDialogHeader, AlertDialogHeader,
AlertDialogOverlay, AlertDialogOverlay,
} from '@chakra-ui/react' } from '@chakra-ui/react'
import { AddIcon, EditIcon } from '@chakra-ui/icons' import { AddIcon } from '@chakra-ui/icons'
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'
import { Lesson } from '../../__data__/model' import { Lesson } from '../../__data__/model'
import { XlSpinner } from '../../components/xl-spinner' import { XlSpinner } from '../../components/xl-spinner'
import { LessonForm } from './components/lessons-form' import { LessonForm } from './components/lessons-form'
import { BreadcrumbsWrapper } from './style'
import { Bar } from './components/bar' import { Bar } from './components/bar'
import { LessonItems } from './components/lesson-items'
import { BreadcrumbsWrapper } from './style'
const features = getFeatures('journal') const features = getFeatures('journal')
@ -67,7 +57,10 @@ const LessonList = () => {
const toastRef = useRef(null) const toastRef = useRef(null)
const createdLessonRef = useRef(null) const createdLessonRef = useRef(null)
const [editLesson, setEditLesson] = useState<Lesson>(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 sorted = useMemo(
() => [...(data?.body || [])]?.sort((a, b) => (a.date > b.date ? 1 : -1)),
[data, data?.body],
)
const lessonCalc = useMemo(() => { const lessonCalc = useMemo(() => {
if (!isSuccess) { if (!isSuccess) {
@ -95,7 +88,7 @@ const LessonList = () => {
} }
} }
return lessonsData.sort((a, b) => a.date < b.date? 1 : -1) return lessonsData.sort((a, b) => (a.date < b.date ? 1 : -1))
}, [groupByDate, isSuccess, sorted]) }, [groupByDate, isSuccess, sorted])
const onSubmit = (lessonData) => { const onSubmit = (lessonData) => {
@ -153,8 +146,8 @@ const LessonList = () => {
if (crLQuery.isSuccess) { if (crLQuery.isSuccess) {
const toastProps = { const toastProps = {
title: 'Лекция создана', title: 'Лекция создана',
description: `Лекция ${createdLessonRef.current.name} успешно создана`, description: `Лекция ${createdLessonRef.current?.name} успешно создана`,
status: 'success' as 'success', status: 'success' as const,
duration: 9000, duration: 9000,
isClosable: true, isClosable: true,
} }
@ -168,8 +161,8 @@ const LessonList = () => {
if (updateLessonRqst.isSuccess) { if (updateLessonRqst.isSuccess) {
const toastProps = { const toastProps = {
title: 'Лекция Обновлена', title: 'Лекция Обновлена',
description: `Лекция ${createdLessonRef.current.name} успешно обновлена`, description: `Лекция ${createdLessonRef.current?.name} успешно обновлена`,
status: 'success' as 'success', status: 'success' as const,
duration: 9000, duration: 9000,
isClosable: true, isClosable: true,
} }
@ -180,7 +173,7 @@ const LessonList = () => {
}, [updateLessonRqst.isSuccess]) }, [updateLessonRqst.isSuccess])
if (isLoading) { if (isLoading) {
return <XlSpinner />; return <XlSpinner />
} }
return ( return (
@ -213,7 +206,7 @@ const LessonList = () => {
colorScheme="red" colorScheme="red"
loadingText="" loadingText=""
isLoading={deletingRqst.isLoading} isLoading={deletingRqst.isLoading}
onClick={() => deleteLesson(lessonToDelete._id)} onClick={() => deleteLesson(lessonToDelete.id)}
ml={3} ml={3}
> >
Delete Delete
@ -240,7 +233,7 @@ const LessonList = () => {
<Box mt="15" mb="15"> <Box mt="15" mb="15">
{showForm ? ( {showForm ? (
<LessonForm <LessonForm
key={editLesson?._id} key={editLesson?.id}
isLoading={crLQuery.isLoading} isLoading={crLQuery.isLoading}
onSubmit={onSubmit} onSubmit={onSubmit}
onCancel={() => { onCancel={() => {
@ -265,7 +258,7 @@ const LessonList = () => {
)} )}
</Box> </Box>
)} )}
{barFeature && sorted?.length && ( {barFeature && sorted?.length > 1 && (
<Box height="300"> <Box height="300">
<Bar <Bar
data={sorted.map((lesson, index) => ({ data={sorted.map((lesson, index) => ({
@ -285,7 +278,7 @@ const LessonList = () => {
</Th> </Th>
)} )}
<Th textAlign="center" width={1}> <Th textAlign="center" width={1}>
Дата {groupByDate ? 'Время' : 'Дата'}
</Th> </Th>
<Th width="100%">Название</Th> <Th width="100%">Название</Th>
{isTeacher(user) && <Th>action</Th>} {isTeacher(user) && <Th>action</Th>}
@ -294,56 +287,14 @@ const LessonList = () => {
</Thead> </Thead>
<Tbody> <Tbody>
{lessonCalc?.map(({ data: lessons, date }) => ( {lessonCalc?.map(({ data: lessons, date }) => (
<React.Fragment key={date}> <LessonItems
{date && <Tr><Td colSpan={isTeacher(user) ? 5 : 3}>{dayjs(date).format('DD MMMM YYYY')}</Td></Tr>} courseId={courseId}
{lessons.map((lesson) => ( date={date}
<Tr key={lesson._id}> isTeacher={isTeacher(user)}
{isTeacher(user) && ( lessons={lessons}
<Td> setlessonToDelete={setlessonToDelete}
<Link key={date}
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> </Tbody>
</Table> </Table>