fix: поправил автоподстановку даты в форму редактирования лекции [#29]
All checks were successful
platform/bro/pipeline/head This commit looks good
All checks were successful
platform/bro/pipeline/head This commit looks good
This commit is contained in:
parent
2d98b55bbc
commit
87c08e18bd
1
src/components/xl-spinner/index.ts
Normal file
1
src/components/xl-spinner/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { XlSpinner } from './xl-spinner';
|
20
src/components/xl-spinner/xl-spinner.tsx
Normal file
20
src/components/xl-spinner/xl-spinner.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
Center,
|
||||||
|
Spinner,
|
||||||
|
} from '@chakra-ui/react'
|
||||||
|
|
||||||
|
export const XlSpinner = () => (
|
||||||
|
<Container maxW="container.xl">
|
||||||
|
<Center h="300px">
|
||||||
|
<Spinner
|
||||||
|
thickness="4px"
|
||||||
|
speed="0.65s"
|
||||||
|
emptyColor="gray.200"
|
||||||
|
color="blue.500"
|
||||||
|
size="xl"
|
||||||
|
/>
|
||||||
|
</Center>
|
||||||
|
</Container>
|
||||||
|
)
|
@ -61,8 +61,8 @@ const CoursesList = () => {
|
|||||||
getValues,
|
getValues,
|
||||||
} = useForm<NewCourseForm>({
|
} = useForm<NewCourseForm>({
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
startDt: '',
|
startDt: dayjs().format('YYYY-MM-DD'),
|
||||||
name: '',
|
name: 'Название',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { lazy } from 'react'
|
import { lazy } from 'react'
|
||||||
|
|
||||||
export const CourseListPage = lazy(/* chank-name="course-details" */() => import('./course-list'));
|
export const CourseListPage = lazy(() => import(/* webpackChunkName: "course-list" */ './course-list'));
|
||||||
|
export const LessonDetailsPage = lazy(() => import(/* webpackChunkName: "lesson-details" */ './lesson-details'));
|
||||||
export const LessonDetailsPage = lazy(/* chank-name="course-details" */() => import('./lesson-details'));
|
export const LessonListPage = lazy(() => import(/* webpackChunkName: "lesson-list" */ './lesson-list'));
|
||||||
export const LessonListPage = lazy(/* chank-name="course-details" */() => import('./lesson-list'));
|
export const UserPage = lazy(() => import(/* webpackChunkName: "user-page" */ './user-page'));
|
||||||
|
|
||||||
export const UserPage = lazy(/* chank-name="course-details" */() => import('./user-page'));
|
|
||||||
|
28
src/pages/lesson-list/components/bar.tsx
Normal file
28
src/pages/lesson-list/components/bar.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { ResponsiveBar } from '@nivo/bar'
|
||||||
|
|
||||||
|
export const Bar = ({ data }) => (
|
||||||
|
<ResponsiveBar
|
||||||
|
data={data}
|
||||||
|
keys={['count']}
|
||||||
|
indexBy="lessonIndex"
|
||||||
|
margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
|
||||||
|
padding={0.3}
|
||||||
|
valueScale={{ type: 'linear' }}
|
||||||
|
indexScale={{ type: 'band', round: true }}
|
||||||
|
colors={{ scheme: 'set3' }}
|
||||||
|
axisTop={null}
|
||||||
|
axisRight={null}
|
||||||
|
labelSkipWidth={12}
|
||||||
|
labelSkipHeight={12}
|
||||||
|
labelTextColor={{
|
||||||
|
from: 'color',
|
||||||
|
modifiers: [['brighter', 1.4]],
|
||||||
|
}}
|
||||||
|
role="application"
|
||||||
|
ariaLabel="График посещаемости лекций"
|
||||||
|
barAriaLabel={(e) =>
|
||||||
|
e.id + ': ' + e.formattedValue + ' on lection: ' + e.indexValue
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)
|
137
src/pages/lesson-list/components/lessons-form.tsx
Normal file
137
src/pages/lesson-list/components/lessons-form.tsx
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useForm, Controller } from 'react-hook-form'
|
||||||
|
import {
|
||||||
|
Box,
|
||||||
|
Card,
|
||||||
|
CardBody,
|
||||||
|
CardHeader,
|
||||||
|
Heading,
|
||||||
|
Button,
|
||||||
|
CloseButton,
|
||||||
|
VStack,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
FormHelperText,
|
||||||
|
FormErrorMessage,
|
||||||
|
Input,
|
||||||
|
} from '@chakra-ui/react'
|
||||||
|
import { AddIcon } from '@chakra-ui/icons'
|
||||||
|
|
||||||
|
import { dateToCalendarFormat } from '../../../utils/time'
|
||||||
|
import { Lesson } from '../../../__data__/model'
|
||||||
|
import { ErrorSpan } from '../style'
|
||||||
|
|
||||||
|
interface NewLessonForm {
|
||||||
|
name: string;
|
||||||
|
date: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface LessonFormProps {
|
||||||
|
lesson?: Partial<Lesson>
|
||||||
|
isLoading: boolean
|
||||||
|
onCancel: () => void
|
||||||
|
onSubmit: (lesson: Lesson) => void
|
||||||
|
error?: string
|
||||||
|
title: string
|
||||||
|
nameButton: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LessonForm = ({
|
||||||
|
lesson,
|
||||||
|
isLoading,
|
||||||
|
onCancel,
|
||||||
|
onSubmit,
|
||||||
|
error,
|
||||||
|
title,
|
||||||
|
nameButton,
|
||||||
|
}: LessonFormProps) => {
|
||||||
|
const {
|
||||||
|
control,
|
||||||
|
handleSubmit,
|
||||||
|
reset,
|
||||||
|
formState: { errors },
|
||||||
|
} = useForm<NewLessonForm>({
|
||||||
|
defaultValues: (lesson && { ...lesson, date: dateToCalendarFormat(lesson.date) }) || {
|
||||||
|
name: '',
|
||||||
|
date: dateToCalendarFormat(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card align="left">
|
||||||
|
<CardHeader display="flex">
|
||||||
|
<Heading as="h2" mt="0">
|
||||||
|
{title}
|
||||||
|
</Heading>
|
||||||
|
<CloseButton
|
||||||
|
ml="auto"
|
||||||
|
onClick={() => {
|
||||||
|
reset()
|
||||||
|
onCancel()
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</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>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<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"
|
||||||
|
isLoading={isLoading}
|
||||||
|
>
|
||||||
|
{nameButton}
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
|
</VStack>
|
||||||
|
|
||||||
|
{error && <ErrorSpan>{error}</ErrorSpan>}
|
||||||
|
</form>
|
||||||
|
</CardBody>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
}
|
3
src/pages/lesson-list/index.ts
Normal file
3
src/pages/lesson-list/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import LessonsList from './lesson-list';
|
||||||
|
|
||||||
|
export default LessonsList;
|
@ -4,31 +4,18 @@ import React, {
|
|||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import { ResponsiveBar } from '@nivo/bar'
|
|
||||||
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'
|
||||||
import { useForm, Controller } from 'react-hook-form'
|
|
||||||
import {
|
import {
|
||||||
Breadcrumb,
|
Breadcrumb,
|
||||||
BreadcrumbItem,
|
BreadcrumbItem,
|
||||||
BreadcrumbLink,
|
BreadcrumbLink,
|
||||||
Container,
|
Container,
|
||||||
Box,
|
Box,
|
||||||
Card,
|
|
||||||
CardBody,
|
|
||||||
CardHeader,
|
|
||||||
Heading,
|
|
||||||
Button,
|
Button,
|
||||||
CloseButton,
|
|
||||||
useToast,
|
useToast,
|
||||||
VStack,
|
|
||||||
FormControl,
|
|
||||||
FormLabel,
|
|
||||||
Toast,
|
Toast,
|
||||||
FormHelperText,
|
|
||||||
FormErrorMessage,
|
|
||||||
Input,
|
|
||||||
TableContainer,
|
TableContainer,
|
||||||
Table,
|
Table,
|
||||||
Thead,
|
Thead,
|
||||||
@ -41,8 +28,6 @@ import {
|
|||||||
MenuItem,
|
MenuItem,
|
||||||
Text,
|
Text,
|
||||||
MenuList,
|
MenuList,
|
||||||
Center,
|
|
||||||
Spinner,
|
|
||||||
AlertDialog,
|
AlertDialog,
|
||||||
AlertDialogBody,
|
AlertDialogBody,
|
||||||
AlertDialogContent,
|
AlertDialogContent,
|
||||||
@ -52,134 +37,22 @@ import {
|
|||||||
} from '@chakra-ui/react'
|
} from '@chakra-ui/react'
|
||||||
import { AddIcon, EditIcon } from '@chakra-ui/icons'
|
import { AddIcon, EditIcon } 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 { qrCode } from '../../assets'
|
||||||
import { Lesson } from '../__data__/model'
|
import { Lesson } from '../../__data__/model'
|
||||||
|
import { XlSpinner } from '../../components/xl-spinner'
|
||||||
|
|
||||||
import { ErrorSpan, BreadcrumbsWrapper } from './style'
|
import { LessonForm } from './components/lessons-form'
|
||||||
|
import { BreadcrumbsWrapper } from './style'
|
||||||
|
import { Bar } from './components/bar'
|
||||||
|
|
||||||
const features = getFeatures('journal')
|
const features = getFeatures('journal')
|
||||||
|
|
||||||
const barFeature = features?.['lesson.bar']
|
const barFeature = features?.['lesson.bar']
|
||||||
const groupByDate = features?.['group.by.date']
|
const groupByDate = features?.['group.by.date']
|
||||||
|
|
||||||
interface NewLessonForm {
|
|
||||||
name: string
|
|
||||||
date: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface LessonFormProps {
|
|
||||||
lesson?: Partial<Lesson>
|
|
||||||
isLoading: boolean
|
|
||||||
onCancel: () => void
|
|
||||||
onSubmit: (lesson: Lesson) => void
|
|
||||||
error?: string
|
|
||||||
title: string
|
|
||||||
nameButton: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const LessonForm = ({
|
|
||||||
lesson,
|
|
||||||
isLoading,
|
|
||||||
onCancel,
|
|
||||||
onSubmit,
|
|
||||||
error,
|
|
||||||
title,
|
|
||||||
nameButton,
|
|
||||||
}: LessonFormProps) => {
|
|
||||||
const {
|
|
||||||
control,
|
|
||||||
handleSubmit,
|
|
||||||
reset,
|
|
||||||
formState: { errors },
|
|
||||||
} = useForm<NewLessonForm>({
|
|
||||||
defaultValues: lesson || {
|
|
||||||
name: '',
|
|
||||||
date: '',
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card align="left">
|
|
||||||
<CardHeader display="flex">
|
|
||||||
<Heading as="h2" mt="0">
|
|
||||||
{title}
|
|
||||||
</Heading>
|
|
||||||
<CloseButton
|
|
||||||
ml="auto"
|
|
||||||
onClick={() => {
|
|
||||||
reset()
|
|
||||||
onCancel()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</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>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<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"
|
|
||||||
isLoading={isLoading}
|
|
||||||
>
|
|
||||||
{nameButton}
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</VStack>
|
|
||||||
|
|
||||||
{error && <ErrorSpan>{error}</ErrorSpan>}
|
|
||||||
</form>
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const LessonList = () => {
|
const LessonList = () => {
|
||||||
const { courseId } = useParams()
|
const { courseId } = useParams()
|
||||||
const user = useAppSelector((s) => s.user)
|
const user = useAppSelector((s) => s.user)
|
||||||
@ -201,7 +74,6 @@ const LessonList = () => {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!groupByDate) {
|
if (!groupByDate) {
|
||||||
return [{ date: '', data: sorted }]
|
return [{ date: '', data: sorted }]
|
||||||
}
|
}
|
||||||
@ -308,19 +180,7 @@ const LessonList = () => {
|
|||||||
}, [updateLessonRqst.isSuccess])
|
}, [updateLessonRqst.isSuccess])
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return <XlSpinner />;
|
||||||
<Container maxW="container.xl">
|
|
||||||
<Center h="300px">
|
|
||||||
<Spinner
|
|
||||||
thickness="4px"
|
|
||||||
speed="0.65s"
|
|
||||||
emptyColor="gray.200"
|
|
||||||
color="blue.500"
|
|
||||||
size="xl"
|
|
||||||
/>
|
|
||||||
</Center>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -494,29 +354,3 @@ const LessonList = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default LessonList
|
export default LessonList
|
||||||
|
|
||||||
const Bar = ({ data }) => (
|
|
||||||
<ResponsiveBar
|
|
||||||
data={data}
|
|
||||||
keys={['count']}
|
|
||||||
indexBy="lessonIndex"
|
|
||||||
margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
|
|
||||||
padding={0.3}
|
|
||||||
valueScale={{ type: 'linear' }}
|
|
||||||
indexScale={{ type: 'band', round: true }}
|
|
||||||
colors={{ scheme: 'set3' }}
|
|
||||||
axisTop={null}
|
|
||||||
axisRight={null}
|
|
||||||
labelSkipWidth={12}
|
|
||||||
labelSkipHeight={12}
|
|
||||||
labelTextColor={{
|
|
||||||
from: 'color',
|
|
||||||
modifiers: [['brighter', 1.4]],
|
|
||||||
}}
|
|
||||||
role="application"
|
|
||||||
ariaLabel="График посещаемости лекций"
|
|
||||||
barAriaLabel={(e) =>
|
|
||||||
e.id + ': ' + e.formattedValue + ' on lection: ' + e.indexValue
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)
|
|
13
src/pages/lesson-list/style.ts
Normal file
13
src/pages/lesson-list/style.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
|
export const BreadcrumbsWrapper = styled.div`
|
||||||
|
padding: 12px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ErrorSpan = styled.span`
|
||||||
|
color: #f9e2e2;
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
background-color: #d32f0b;
|
||||||
|
border-radius: 11px;
|
||||||
|
`
|
@ -9,10 +9,8 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Center,
|
Center,
|
||||||
Container,
|
Container,
|
||||||
Heading,
|
|
||||||
Spinner,
|
Spinner,
|
||||||
Text,
|
Text,
|
||||||
Stack,
|
|
||||||
} from '@chakra-ui/react'
|
} from '@chakra-ui/react'
|
||||||
import { UserCard } from '../components/user-card'
|
import { UserCard } from '../components/user-card'
|
||||||
|
|
||||||
|
3
src/utils/time.ts
Normal file
3
src/utils/time.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
|
export const dateToCalendarFormat = (date?: string) => dayjs(date).format('YYYY-MM-DDTHH:mm')
|
Loading…
Reference in New Issue
Block a user