diff --git a/apps/schools/domains/circle/components/changeCircleForm/constants.ts b/apps/schools/domains/circle/components/changeCircleForm/constants.ts new file mode 100644 index 00000000..1bf8b2a0 --- /dev/null +++ b/apps/schools/domains/circle/components/changeCircleForm/constants.ts @@ -0,0 +1,3 @@ +export const CIRCLE_NAME: string = 'circle_name' +export const CIRCLE_ADDRESS: string = 'circle_address' +export const ADDRESS_ROOM: string = 'address_room' diff --git a/apps/schools/domains/circle/components/changeCircleForm/hooks.ts b/apps/schools/domains/circle/components/changeCircleForm/hooks.ts new file mode 100644 index 00000000..b0b37e49 --- /dev/null +++ b/apps/schools/domains/circle/components/changeCircleForm/hooks.ts @@ -0,0 +1,30 @@ +import { useMemo } from 'react' +import { PleaseInputAddressMsg, PleaseInputCircleNameMsg } from '@domains/user/components/auth/constants/message' +import { ValidatorsMap } from '@domains/common/redux/interfaces' +import { getGreaterValidator } from '@domains/common/utils/validators' + +export const useChangeCircleFormValidators = () => { + return useMemo(() => { + return { + name: [ + { + required: true, + message: PleaseInputCircleNameMsg, + whitespace: true, + type: 'string', + }, + getGreaterValidator(200), + ], + address: [ + { + required: true, + message: PleaseInputAddressMsg, + whitespace: true, + type: 'string', + }, + getGreaterValidator(200), + ], + room: [getGreaterValidator(55)], + } + }, [this]) +} diff --git a/apps/schools/domains/circle/components/changeCircleForm/index.tsx b/apps/schools/domains/circle/components/changeCircleForm/index.tsx new file mode 100644 index 00000000..f458bd3e --- /dev/null +++ b/apps/schools/domains/circle/components/changeCircleForm/index.tsx @@ -0,0 +1,155 @@ +import { Form, Typography, Input as AntdInput, Row, Spin } from 'antd' +import React, { useState } from 'react' +import { Input } from '@domains/common/components/input' +import styles from './styles/styles.module.scss' +import { Button } from '@domains/common/components/button' +import { useChangeCircleFormValidators } from './hooks' +import { useGetAllCirclesQuery } from '@domains/organization/redux/organizationApi' +import { useOrganization } from '@domains/organization/providers/organizationProvider' +import { WithTooltip } from '@domains/common/components/tooltip/withTooltip' +import { TOOLTIP_MARGIN } from './styles/styles' +import { isValidFormCheck } from '@domains/common/utils/form' +import { CIRCLE_NAME, CIRCLE_ADDRESS, ADDRESS_ROOM } from './constants' +import classnames from 'classnames' +import { AimOutlined } from '@ant-design/icons' +import { Select } from '@domains/common/components/select' +import { handleSubmitForm } from '../../handlers/circleUpdate' +import { useChangeCircleMutation, useGetCircleQuery } from '../../redux/circleApi' +import { getVarsForAddressColumn } from '@domains/common/utils/geo' +import { getUuidFromUrl } from '@domains/common/utils/getUuidFromUrl' + +export const ChangeCircleForm = () => { + const validators = useChangeCircleFormValidators() + const { organizationId } = useOrganization() + const [form] = Form.useForm() + const [isFormValid, setIsFormValid] = useState(false) + const [mutation] = useChangeCircleMutation() + + const circleId = getUuidFromUrl()[0] + + const circleData = useGetCircleQuery({ + circle_id: circleId, + }) + const currentCircle = circleData?.data?.circle + + const circlesData = useGetAllCirclesQuery({ + organization_id: organizationId, + }) + const circlesAddresses = Array.from( + new Set(circlesData?.data?.results.map((x) => getVarsForAddressColumn(x.address)[0])), + ) + + const initialValues = { + [CIRCLE_NAME]: currentCircle?.name, + [CIRCLE_ADDRESS]: getVarsForAddressColumn(currentCircle?.address ?? '')[0], + [ADDRESS_ROOM]: getVarsForAddressColumn(currentCircle?.address ?? '')[1], + } + + const validationCheck = () => { + setIsFormValid(isValidFormCheck(form, [], initialValues)) + } + + return !circleData.isLoading ? ( + +
+
{ + handleSubmitForm(circleId, form, mutation).then((isSucceed) => { + if (isSucceed) window.location.href = `/circle/${circleId}` + }) + }} + layout='vertical' + > + Редактирование кружка + + + * Название + + } + name={CIRCLE_NAME} + className={styles.label} + rules={validators.name} + initialValue={initialValues[CIRCLE_NAME]} + > + + + + + + {!circlesData.isLoading ? ( + <> + + + * Адрес + + } + name={CIRCLE_ADDRESS} + initialValue={initialValues[CIRCLE_ADDRESS]} + className={classnames(styles.label, styles.address)} + rules={validators.address} + > + + + + + + + ) : ( + + )} + + + + + +
+
+
+ ) : ( + + ) +} diff --git a/apps/schools/domains/circle/components/changeCircleForm/styles/styles.module.scss b/apps/schools/domains/circle/components/changeCircleForm/styles/styles.module.scss new file mode 100644 index 00000000..168c0ec8 --- /dev/null +++ b/apps/schools/domains/circle/components/changeCircleForm/styles/styles.module.scss @@ -0,0 +1,71 @@ +@import '../../../../common/components/styles/abstracts/colors'; + +.mainRow { + height: 100px; + justify-content: space-between; + + .formContainer { + width: 700px; + + .table { + max-width: 550px; + + .requiredMark { + color: $color-required-mark; + } + + .label { + font-family: 'Roboto', sans-serif; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 22px; + } + + .complexInputContainer { + width: 125%; + + .complexInput { + width: 76%; + + .address { + width: 65%; + border-radius: 0; + + .input { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + } + + .room { + width: 35%; + + .input { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + } + } + + .mapButton { + width: 24%; + margin-top: 38px; + color: $main-blue-color; + padding-left: 1%; + } + } + + + .button { + width: 40%; + text-align: center; + font-family: 'Roboto', sans-serif; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 24px; + } + } + } +} \ No newline at end of file diff --git a/apps/schools/domains/circle/components/changeCircleForm/styles/styles.ts b/apps/schools/domains/circle/components/changeCircleForm/styles/styles.ts new file mode 100644 index 00000000..77493475 --- /dev/null +++ b/apps/schools/domains/circle/components/changeCircleForm/styles/styles.ts @@ -0,0 +1 @@ +export const TOOLTIP_MARGIN = '47px' diff --git a/apps/schools/domains/circle/components/createCircleForm/index.tsx b/apps/schools/domains/circle/components/createCircleForm/index.tsx index 6e8154c5..2b8378dc 100644 --- a/apps/schools/domains/circle/components/createCircleForm/index.tsx +++ b/apps/schools/domains/circle/components/createCircleForm/index.tsx @@ -13,7 +13,7 @@ import { CIRCLE_NAME, CIRCLE_ADDRESS, ADDRESS_ROOM } from './constants' import classnames from 'classnames' import { AimOutlined } from '@ant-design/icons' import { Select } from '@domains/common/components/select' -import { handleSubmitForm } from '../../handlers/circle' +import { handleSubmitForm } from '../../handlers/circleCreate' import { useCreateCircleMutation } from '../../redux/circleApi' import { getVarsForAddressColumn } from '@domains/common/utils/geo' @@ -31,7 +31,7 @@ export const CreateCircleForm = () => { ) const validationCheck = () => { - setIsFormValid(isValidFormCheck(form, [CIRCLE_NAME])) + setIsFormValid(isValidFormCheck(form, [CIRCLE_NAME, CIRCLE_ADDRESS])) } return ( @@ -88,10 +88,10 @@ export const CreateCircleForm = () => { customType={'selectInput'} className={styles.select} loading={circlesData.isLoading} - options={circlesAddresses?.map((x: string | undefined) => { + options={circlesAddresses?.map((address: string | undefined) => { return { - value: x, - label: x, + value: address, + label: address, } })} /> diff --git a/apps/schools/domains/circle/components/currentCircle/index.tsx b/apps/schools/domains/circle/components/currentCircle/index.tsx index 20e34f6d..c2c85aeb 100644 --- a/apps/schools/domains/circle/components/currentCircle/index.tsx +++ b/apps/schools/domains/circle/components/currentCircle/index.tsx @@ -22,6 +22,7 @@ import android from '@public/image/Android.svg' import { searchColumns } from './constants' import { CurrentCircleRowType } from './interfaces' import styles from './styles/styles.module.scss' +import { getVarsForAddressColumn } from '@domains/common/utils/geo' const CurrentCircle = () => { const [isModalVisible, setIsModalVisible] = useState(false) @@ -56,6 +57,7 @@ const CurrentCircle = () => { }) const countAllQueries = sumObjectValues(queriesCount) + const addressVars = getVarsForAddressColumn(circle?.circle.address ?? '') return ( <> @@ -64,7 +66,7 @@ const CurrentCircle = () => { - {circle?.circle.address} + {`${addressVars[0]}, ${addressVars[1]}`} Заявки
Всего
diff --git a/apps/schools/domains/circle/handlers/circle.ts b/apps/schools/domains/circle/handlers/circleCreate.ts similarity index 100% rename from apps/schools/domains/circle/handlers/circle.ts rename to apps/schools/domains/circle/handlers/circleCreate.ts diff --git a/apps/schools/domains/circle/handlers/circleUpdate.ts b/apps/schools/domains/circle/handlers/circleUpdate.ts new file mode 100644 index 00000000..a9f3265e --- /dev/null +++ b/apps/schools/domains/circle/handlers/circleUpdate.ts @@ -0,0 +1,27 @@ +import { FormInstance, message } from 'antd' +import { LoadingRequestMsg, SuccessUpdateCircleMsg } from '@domains/user/components/auth/constants/message' +import { removeEmpty } from '@domains/common/utils/form' +import { CIRCLE_NAME, CIRCLE_ADDRESS, ADDRESS_ROOM } from '../components/changeCircleForm/constants' +import { withLoadingMessage } from '@domains/common/utils/loading' +import { ADDRESS_SEPARATOR } from '@domains/common/utils/geo' + +export async function handleSubmitForm(circleId: string, formComponent: FormInstance, mutation: any) { + const response = await withLoadingMessage( + LoadingRequestMsg, + mutation, + removeEmpty({ + circle_id: circleId, + name: formComponent.getFieldValue(CIRCLE_NAME), + address: `${formComponent.getFieldValue(CIRCLE_ADDRESS)}${ADDRESS_SEPARATOR}${formComponent.getFieldValue( + ADDRESS_ROOM, + )}`, + }), + ) + + if ('data' in response) { + message.success(SuccessUpdateCircleMsg) + return true + } + + return false +} diff --git a/apps/schools/domains/circle/redux/circleApi.ts b/apps/schools/domains/circle/redux/circleApi.ts index 48537497..31918876 100644 --- a/apps/schools/domains/circle/redux/circleApi.ts +++ b/apps/schools/domains/circle/redux/circleApi.ts @@ -6,6 +6,7 @@ import { CircleStudentsData, CreateCircleData, CreateCircleInviteStudentData, + ChangeCircleData, } from './interfaces' import { GetCircle, GetQueryStatus, GetStudent } from '@domains/common/redux/serializers' @@ -25,6 +26,13 @@ const circleApi = commonApi.injectEndpoints({ body: data, }), }), + changeCircle: build.mutation<{ circle: GetCircle }, ChangeCircleData>({ + query: (data) => ({ + url: `/organization-management/circles/${data.circle_id}`, + method: 'PATCH', + body: data, + }), + }), getCircle: build.query<{ circle: GetCircle }, CircleData>({ query: (params) => ({ url: `/organization-management/circles/${params.circle_id}`, @@ -61,4 +69,5 @@ export const { useGetCircleQuery, useDeleteCircleMutation, useInviteStudentMutation, + useChangeCircleMutation, } = circleApi diff --git a/apps/schools/domains/circle/redux/interfaces.ts b/apps/schools/domains/circle/redux/interfaces.ts index 37341f8d..58c26a01 100644 --- a/apps/schools/domains/circle/redux/interfaces.ts +++ b/apps/schools/domains/circle/redux/interfaces.ts @@ -26,6 +26,13 @@ export interface CreateCircleData { location: string } +export interface ChangeCircleData { + name?: string + address?: string + location?: string + circle_id: string +} + export interface AllCirclesIcalData extends BasePaginationData { id?: string organization?: string diff --git a/apps/schools/domains/common/components/select/index.tsx b/apps/schools/domains/common/components/select/index.tsx index e54b8cc3..62e2feeb 100644 --- a/apps/schools/domains/common/components/select/index.tsx +++ b/apps/schools/domains/common/components/select/index.tsx @@ -22,9 +22,11 @@ export const Select: React.FC = (props) => {
{children} @@ -57,6 +59,7 @@ export const Select: React.FC = (props) => { className={classNames(selectStyleDictionary['selectDefault']?.select, className)} {...restProps} showSearch={true} + disabled={disabled} onSearch={handleSearch} onSelect={() => setAddressText('')} placeholder={placeholder} @@ -72,9 +75,11 @@ export const Select: React.FC = (props) => {
{children} diff --git a/apps/schools/domains/common/utils/form.ts b/apps/schools/domains/common/utils/form.ts index 8d3b9452..0e64d7b8 100644 --- a/apps/schools/domains/common/utils/form.ts +++ b/apps/schools/domains/common/utils/form.ts @@ -6,10 +6,13 @@ export function checkIfNotEmptyValue(x: any) { return Boolean(Array.isArray(x) ? x.length !== 0 : x) } -export function isValidFormCheck(form: FormInstance, required_fields: string[]) { - return Object.entries(form.getFieldsValue()).every( - (x) => checkIfNotEmptyValue(x[1]) || !required_fields.includes(x[0]), - ) +export function isValidFormCheck(form: FormInstance, required_fields: string[], initial_values: any = {}) { + if (Object.keys(initial_values).length === 0) + return Object.entries(form.getFieldsValue()).every( + (x) => checkIfNotEmptyValue(x[1]) || !required_fields.includes(x[0]), + ) + + return !Object.entries(form.getFieldsValue()).every((x) => x[1] === initial_values[x[0]]) } export function isPhoneValid(form: FormInstance, field_name: string) { diff --git a/apps/schools/domains/user/components/auth/constants/message.ts b/apps/schools/domains/user/components/auth/constants/message.ts index 070a1da6..233e231e 100644 --- a/apps/schools/domains/user/components/auth/constants/message.ts +++ b/apps/schools/domains/user/components/auth/constants/message.ts @@ -29,3 +29,4 @@ export const PleaseInputYourEmailMsg = 'Пожалуйста, введите в export const PleaseSelectOneOfOptionsMsg = 'Пожалуйста, выберите один из вариантов' export const SuccessInviteEmployeeMsg = 'Приглашение отправлено' export const SuccessCreateCircleMsg = 'Кружок успешно создан' +export const SuccessUpdateCircleMsg = 'Кружок успешно изменён' diff --git a/apps/schools/pages/circle/[id]/change/index.tsx b/apps/schools/pages/circle/[id]/change/index.tsx index 48c50a59..85606d86 100644 --- a/apps/schools/pages/circle/[id]/change/index.tsx +++ b/apps/schools/pages/circle/[id]/change/index.tsx @@ -1,11 +1,22 @@ -import React from "react"; +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 {ChangeCircleForm} from "@domains/circle/components/changeCircleForm"; -const Index = () => { +export const Change = () => { return ( -
+ <> + + Редактирование кружка + + + + + + + + ) +} -
- ); -}; - -export default Index; +export default Change