From 9563762eab04ab2deb7e9794f44ba577bfb3a62f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB?= <33755295+zavarin-michael@users.noreply.github.com> Date: Sat, 9 Mar 2024 22:58:00 +0500 Subject: [PATCH] added change and delete buttons to student page + page for changing student name + fixes in common components --- .../deleteModal/styles/styles.module.scss | 3 +- .../organization/redux/organizationApi.ts | 1 + .../components/changeStudentForm/constants.ts | 1 + .../components/changeStudentForm/hooks.ts | 21 ++++ .../components/changeStudentForm/index.tsx | 98 +++++++++++++++++++ .../styles/styles.module.scss | 20 ++++ .../components/createStudentForm/index.tsx | 2 +- .../components/currentStudent/index.tsx | 44 +++++++-- .../currentStudent/styles/styles.module.scss | 4 +- .../handlers/{student.ts => studentCreate.ts} | 4 +- .../domains/student/handlers/studentPatch.ts | 27 +++++ .../domains/student/redux/interfaces.ts | 8 ++ .../domains/student/redux/studentApi.ts | 28 ++++++ .../user/components/auth/constants/message.ts | 3 + .../pages/student/[id]/change/index.tsx | 22 +++++ 15 files changed, 271 insertions(+), 15 deletions(-) create mode 100644 apps/schools/domains/student/components/changeStudentForm/constants.ts create mode 100644 apps/schools/domains/student/components/changeStudentForm/hooks.ts create mode 100644 apps/schools/domains/student/components/changeStudentForm/index.tsx create mode 100644 apps/schools/domains/student/components/changeStudentForm/styles/styles.module.scss rename apps/schools/domains/student/handlers/{student.ts => studentCreate.ts} (90%) create mode 100644 apps/schools/domains/student/handlers/studentPatch.ts create mode 100644 apps/schools/domains/student/redux/interfaces.ts create mode 100644 apps/schools/domains/student/redux/studentApi.ts create mode 100644 apps/schools/pages/student/[id]/change/index.tsx diff --git a/apps/schools/domains/common/components/deleteModal/styles/styles.module.scss b/apps/schools/domains/common/components/deleteModal/styles/styles.module.scss index 24033a86..685ec268 100644 --- a/apps/schools/domains/common/components/deleteModal/styles/styles.module.scss +++ b/apps/schools/domains/common/components/deleteModal/styles/styles.module.scss @@ -39,6 +39,7 @@ } .deleteButton { - width: 160px; + width: auto; + padding: 7px; } } diff --git a/apps/schools/domains/organization/redux/organizationApi.ts b/apps/schools/domains/organization/redux/organizationApi.ts index 3ceb26ce..7242e9da 100644 --- a/apps/schools/domains/organization/redux/organizationApi.ts +++ b/apps/schools/domains/organization/redux/organizationApi.ts @@ -87,6 +87,7 @@ const organizationApi = commonApi.injectEndpoints({ url: `/organization-management/organizations/students/${data.student_id}`, method: 'GET', }), + providesTags: (result, error, arg) => [{ type: 'Student', id: arg.student_id }], }), getTeacher: build.query<{ teacher: GetTeacher }, TeacherData>({ query: (data) => ({ diff --git a/apps/schools/domains/student/components/changeStudentForm/constants.ts b/apps/schools/domains/student/components/changeStudentForm/constants.ts new file mode 100644 index 00000000..59c639e2 --- /dev/null +++ b/apps/schools/domains/student/components/changeStudentForm/constants.ts @@ -0,0 +1 @@ +export const STUDENT_NAME = 'student_name' diff --git a/apps/schools/domains/student/components/changeStudentForm/hooks.ts b/apps/schools/domains/student/components/changeStudentForm/hooks.ts new file mode 100644 index 00000000..67331007 --- /dev/null +++ b/apps/schools/domains/student/components/changeStudentForm/hooks.ts @@ -0,0 +1,21 @@ +import { useMemo } from 'react' +import { ValidatorsMap } from '@domains/common/redux/interfaces' +import { PleaseInputStudentNameMsg } from '@domains/user/components/auth/constants/message' +import { getGreaterValidator } from '@domains/common/utils/validators' +import { STUDENT_NAME } from '@domains/student/components/changeStudentForm/constants' + +export const useChangeStudentFormValidators = () => { + return useMemo(() => { + return { + [STUDENT_NAME]: [ + { + required: false, + message: PleaseInputStudentNameMsg, + whitespace: true, + type: 'string', + }, + getGreaterValidator(200), + ], + } + }, [this]) +} diff --git a/apps/schools/domains/student/components/changeStudentForm/index.tsx b/apps/schools/domains/student/components/changeStudentForm/index.tsx new file mode 100644 index 00000000..393c480a --- /dev/null +++ b/apps/schools/domains/student/components/changeStudentForm/index.tsx @@ -0,0 +1,98 @@ +import React, { useEffect, useState } from 'react' +import router from 'next/router' +import { Col, Form, Row, Spin, Typography } from 'antd' +import { Button } from '@domains/common/components/button' +import styles from './styles/styles.module.scss' +import Image from 'next/image' +import duckEmptyPage from '@public/image/duckEmptyPage.svg' + +import { isValidFormCheck } from '@domains/common/utils/form' +import { Input } from '@domains/common/components/input' + +import { useGetStudentQuery } from '@domains/organization/redux/organizationApi' +import { STUDENT_NAME } from '../createStudentForm/constants' +import { getUuidFromUrl } from '@domains/common/utils/getUuidFromUrl' +import { handleSubmitForm } from '@domains/student/handlers/studentPatch' +import { useUpdateStudentByIdMutation } from '@domains/student/redux/studentApi' +import { useChangeStudentFormValidators } from '@domains/student/components/changeStudentForm/hooks' +import { ErrorType } from '@store/commonApi' + +export function ChangeStudentForm() { + const uuid = getUuidFromUrl() + const { data: student, error: studentError, isFetching } = useGetStudentQuery({ student_id: uuid[0] }) + const [form] = Form.useForm() + const [isFormValid, setIsFormValid] = useState(false) + const validators = useChangeStudentFormValidators() + const [mutation] = useUpdateStudentByIdMutation() + + const initialValues = { + [STUDENT_NAME]: student?.student.name ?? '', + } + + useEffect(() => { + if (studentError && (studentError as ErrorType).status == 404) { + router.push('/student') + } + }, [studentError]) + + if (uuid.length === 0) router.push('/404') + + const validationCheck = () => { + setIsFormValid(isValidFormCheck(form, [], initialValues)) + } + + return ( + + {'Duck + + + Редактирование обучающегося + + + {!isFetching ? ( +
{ + handleSubmitForm(uuid[0], form, mutation).then((isSuccess) => { + if (isSuccess) router.push(`/student/${uuid[0]}`) + }) + }} + layout='vertical' + > + + + + + + + + + +
+ ) : ( + + )} + +
+ ) +} diff --git a/apps/schools/domains/student/components/changeStudentForm/styles/styles.module.scss b/apps/schools/domains/student/components/changeStudentForm/styles/styles.module.scss new file mode 100644 index 00000000..b0497666 --- /dev/null +++ b/apps/schools/domains/student/components/changeStudentForm/styles/styles.module.scss @@ -0,0 +1,20 @@ +.baseRowContainer { + padding-bottom: 50px; + + .infoContainer { + margin-left: 70px; + max-width: 600px; + + .title { + margin-bottom: 50px; + } + + .itemContainer { + margin-bottom: 30px; + } + + .buttonsContainer { + gap: 20px; + } + } +} diff --git a/apps/schools/domains/student/components/createStudentForm/index.tsx b/apps/schools/domains/student/components/createStudentForm/index.tsx index de4836b1..6e3bb8d1 100644 --- a/apps/schools/domains/student/components/createStudentForm/index.tsx +++ b/apps/schools/domains/student/components/createStudentForm/index.tsx @@ -15,7 +15,7 @@ import { STUDENT_NAME, STUDENT_PHONE, } from '@domains/student/components/createStudentForm/constants' -import { handleSubmitForm } from '@domains/student/handlers/student' +import { handleSubmitForm } from '@domains/student/handlers/studentCreate' import { WithTooltip } from '@domains/common/components/tooltip/withTooltip' import { TOOLTIP_MARGIN_TOP } from '@domains/student/components/createStudentForm/styles/constants' import { Select } from '@domains/common/components/select' diff --git a/apps/schools/domains/student/components/currentStudent/index.tsx b/apps/schools/domains/student/components/currentStudent/index.tsx index d5222ca1..885fa6f1 100644 --- a/apps/schools/domains/student/components/currentStudent/index.tsx +++ b/apps/schools/domains/student/components/currentStudent/index.tsx @@ -12,14 +12,15 @@ import router from 'next/router' import duckEmptyPage from '@public/image/duckEmptyPage.svg' import { Button } from '@domains/common/components/button' import { Field } from '@domains/common/components/field' +import { useDeleteStudentMutation } from '@domains/student/redux/studentApi' +import { ActionBar } from '@domains/common/components/stickyBlock/actionBar' +import DeleteModal from '@domains/common/components/deleteModal' const CurrentStudent = () => { const [isModalVisible, setIsModalVisible] = useState(false) - // const [mutation, isDeleteFinished] = useDeleteCircleMutation() + const [mutation, isDeleteFinished] = useDeleteStudentMutation() const uuid = getUuidFromUrl() - console.log(uuid) - const { data: student, error: studentError, isLoading } = useGetStudentQuery({ student_id: uuid[0] }) useEffect(() => { @@ -28,7 +29,7 @@ const CurrentStudent = () => { } }, [studentError]) - // if (isDeleteFinished.isSuccess) return null + if (isDeleteFinished.isSuccess) return null if (uuid.length === 0) router.push('/404') return ( @@ -44,7 +45,7 @@ const CurrentStudent = () => { searchTrigger={false} > - + {'Duck @@ -58,10 +59,6 @@ const CurrentStudent = () => { fieldValue={student?.student.student_profile?.phone} /> - - @@ -82,6 +79,35 @@ const CurrentStudent = () => { + router.push(`/student/${uuid[0]}/change`)} + > + Редактировать профиль + , + , + ]} + /> + ) } diff --git a/apps/schools/domains/student/components/currentStudent/styles/styles.module.scss b/apps/schools/domains/student/components/currentStudent/styles/styles.module.scss index b6647707..39d61887 100644 --- a/apps/schools/domains/student/components/currentStudent/styles/styles.module.scss +++ b/apps/schools/domains/student/components/currentStudent/styles/styles.module.scss @@ -37,7 +37,7 @@ height: initial; margin-bottom: 42px; - .queriesBlock { + .infoBlock { padding-right: 30px; @media (max-width: 992px) { @@ -88,7 +88,7 @@ display: flex; flex-direction: column; gap: 15px; - margin: 30px 23px 0px 30px; + margin: 30px 23px 0 30px; position: relative; } diff --git a/apps/schools/domains/student/handlers/student.ts b/apps/schools/domains/student/handlers/studentCreate.ts similarity index 90% rename from apps/schools/domains/student/handlers/student.ts rename to apps/schools/domains/student/handlers/studentCreate.ts index bdfe1feb..03947440 100644 --- a/apps/schools/domains/student/handlers/student.ts +++ b/apps/schools/domains/student/handlers/studentCreate.ts @@ -1,5 +1,5 @@ import { FormInstance, message } from 'antd' -import { LoadingRequestMsg, SuccessInviteEmployeeMsg } from '@domains/user/components/auth/constants/message' +import { LoadingRequestMsg, SuccessCreateStudentMsg } from '@domains/user/components/auth/constants/message' import { CIRCLES, PARENT_EMAIL, @@ -40,7 +40,7 @@ export async function handleSubmitForm(form: FormInstance, mutation: any) { ) if (isSuccess) { - message.success(SuccessInviteEmployeeMsg) + message.success(SuccessCreateStudentMsg) } return isSuccess diff --git a/apps/schools/domains/student/handlers/studentPatch.ts b/apps/schools/domains/student/handlers/studentPatch.ts new file mode 100644 index 00000000..a00f2f2a --- /dev/null +++ b/apps/schools/domains/student/handlers/studentPatch.ts @@ -0,0 +1,27 @@ +import { FormInstance, message } from 'antd' +import { LoadingRequestMsg, SuccessUpdateStudentMsg } from '@domains/user/components/auth/constants/message' +import { removeEmpty } from '@domains/common/utils/form' +import { withLoadingMessage } from '@domains/common/utils/loading' +import { STUDENT_NAME } from '@domains/student/components/changeStudentForm/constants' + +export async function handleSubmitForm(studentId: string, form: FormInstance, mutation: any) { + const isSuccess = await withLoadingMessage( + LoadingRequestMsg, + async () => { + let response = await mutation( + removeEmpty({ + student_id: studentId, + name: form.getFieldValue(STUDENT_NAME), + }), + ) + return 'data' in response + }, + [], + ) + + if (isSuccess) { + message.success(SuccessUpdateStudentMsg) + } + + return isSuccess +} diff --git a/apps/schools/domains/student/redux/interfaces.ts b/apps/schools/domains/student/redux/interfaces.ts new file mode 100644 index 00000000..27983791 --- /dev/null +++ b/apps/schools/domains/student/redux/interfaces.ts @@ -0,0 +1,8 @@ +export interface DeleteStudentData { + student_id: string +} + +export interface UpdateStudentData { + student_id?: string + name?: string +} diff --git a/apps/schools/domains/student/redux/studentApi.ts b/apps/schools/domains/student/redux/studentApi.ts new file mode 100644 index 00000000..2e9159ad --- /dev/null +++ b/apps/schools/domains/student/redux/studentApi.ts @@ -0,0 +1,28 @@ +import { commonApi } from '@store/commonApi' +import { DeleteStudentData, UpdateStudentData } from './interfaces' +import { GetStudent } from '@domains/common/redux/serializers' + +const organizationApi = commonApi.injectEndpoints({ + endpoints: (build) => ({ + deleteStudent: build.mutation<{}, DeleteStudentData>({ + query: (data) => ({ + url: `/students-management/students/${data.student_id}`, + method: 'DELETE', + }), + invalidatesTags: [{ type: 'Student', id: 'LIST' }], + }), + updateStudentById: build.mutation<{ student: GetStudent }, UpdateStudentData>({ + query: (data) => ({ + url: `/students-management/students/${data.student_id}`, + method: 'PATCH', + body: data, + }), + invalidatesTags: (result, error, arg) => [ + { type: 'Student', id: 'LIST' }, + { type: 'Student', id: arg.student_id }, + ], + }), + }), +}) + +export const { useDeleteStudentMutation, useUpdateStudentByIdMutation } = organizationApi diff --git a/apps/schools/domains/user/components/auth/constants/message.ts b/apps/schools/domains/user/components/auth/constants/message.ts index 99db8356..221eda4b 100644 --- a/apps/schools/domains/user/components/auth/constants/message.ts +++ b/apps/schools/domains/user/components/auth/constants/message.ts @@ -16,6 +16,7 @@ export const SuccessSignInMsg = 'Вы успешно вошли в аккаун export const SuccessResetPasswordMsg = 'Вы успешно сменили пароль' export const SuccessRegistrationMsg = 'Вы успешно зарегистрировались' export const PleaseInputYourNameMsg = 'Пожалуйста, введите ваше Ф. И. О.' +export const PleaseInputStudentNameMsg = 'Пожалуйста, введите ваше Ф. И. О. обучающегося' export const PersonNameMustContainMsg = 'Введен недопустимый символ' export const PersonNameMustNotStartOrAndMsg = 'ФИО не может начинаться с этого символа' export const PleaseInputCircleNameMsg = 'Пожалуйста, введите название кружка' @@ -30,4 +31,6 @@ export const PleaseSelectOneOfOptionsMsg = 'Пожалуйста, выберит export const SuccessInviteEmployeeMsg = 'Приглашение отправлено' export const SuccessCreateCircleMsg = 'Кружок успешно создан' export const SuccessUpdateCircleMsg = 'Кружок успешно изменён' +export const SuccessCreateStudentMsg = 'Обучающийся успешно создан' +export const SuccessUpdateStudentMsg = 'Обучающийся успешно изменён' export const SuccessUpdateUserProfileMsg = 'Ваш профиль успешно изменён' diff --git a/apps/schools/pages/student/[id]/change/index.tsx b/apps/schools/pages/student/[id]/change/index.tsx new file mode 100644 index 00000000..3638b830 --- /dev/null +++ b/apps/schools/pages/student/[id]/change/index.tsx @@ -0,0 +1,22 @@ +import React from 'react' +import Head from 'next/head' +import { PageContent } from '@domains/common/components/containers/PageContent' +import { OrganizationRequired } from '@domains/common/components/containers/OrganizationRequired' +import { ChangeStudentForm } from '@domains/student/components/changeStudentForm' + +export const Change = () => { + return ( + <> + + Редактирование обучающегося + + + + + + + + ) +} + +export default Change