From 9b0cc3107bf7b155787cb38ac11475488017e920 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:26:41 +0300 Subject: [PATCH] F: Fix forms that are subject to react compiler problems --- rsconcept/frontend/src/backend/library/api.ts | 16 ++- .../src/backend/library/useUpdateItem.tsx | 2 +- .../EditorConstituenta/FormConstituenta.tsx | 34 +++-- .../EditorRSFormCard/FormRSForm.tsx | 129 ++++++++---------- .../src/pages/RegisterPage/FormSignup.tsx | 8 +- rsconcept/frontend/src/utils/constants.ts | 1 - 6 files changed, 91 insertions(+), 99 deletions(-) diff --git a/rsconcept/frontend/src/backend/library/api.ts b/rsconcept/frontend/src/backend/library/api.ts index f85c73d3..fbd522c1 100644 --- a/rsconcept/frontend/src/backend/library/api.ts +++ b/rsconcept/frontend/src/backend/library/api.ts @@ -72,8 +72,20 @@ export type ICreateLibraryItemDTO = z.infer; /** * Represents update data for editing {@link ILibraryItem}. */ -export interface IUpdateLibraryItemDTO - extends Omit {} +export const UpdateLibraryItemSchema = z.object({ + id: z.number(), + item_type: z.nativeEnum(LibraryItemType), + title: z.string().nonempty(errors.requiredField), + alias: z.string().nonempty(errors.requiredField), + comment: z.string(), + visible: z.boolean(), + read_only: z.boolean() +}); + +/** + * Represents update data for editing {@link ILibraryItem}. + */ +export type IUpdateLibraryItemDTO = z.infer; /** * Create version metadata in persistent storage. diff --git a/rsconcept/frontend/src/backend/library/useUpdateItem.tsx b/rsconcept/frontend/src/backend/library/useUpdateItem.tsx index 4e0881c0..188fa490 100644 --- a/rsconcept/frontend/src/backend/library/useUpdateItem.tsx +++ b/rsconcept/frontend/src/backend/library/useUpdateItem.tsx @@ -32,6 +32,6 @@ export const useUpdateItem = () => { } }); return { - updateItem: (data: IUpdateLibraryItemDTO) => mutation.mutate(data) + updateItem: (data: IUpdateLibraryItemDTO, onSuccess?: () => void) => mutation.mutate(data, { onSuccess }) }; }; diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx index d8dd51f5..72e7592f 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta/FormConstituenta.tsx @@ -1,7 +1,8 @@ +'use no memo'; // TODO: remove when react hook forms are compliant with react compiler 'use client'; import { zodResolver } from '@hookform/resolvers/zod'; -import { useEffect, useLayoutEffect, useState } from 'react'; +import { useEffect, useLayoutEffect, useMemo, useState } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { toast } from 'react-toastify'; @@ -50,19 +51,26 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen const [localParse, setLocalParse] = useState(undefined); - const typification = localParse - ? labelTypification({ - isValid: localParse.parseResult, - resultType: localParse.typification, - args: localParse.args - }) - : labelCstTypification(activeCst); + const typification = useMemo( + () => + localParse + ? labelTypification({ + isValid: localParse.parseResult, + resultType: localParse.typification, + args: localParse.args + }) + : labelCstTypification(activeCst), + [localParse, activeCst] + ); - const typeInfo = { - alias: activeCst.alias, - result: localParse ? localParse.typification : activeCst.parse.typification, - args: localParse ? localParse.args : activeCst.parse.args - }; + const typeInfo = useMemo( + () => ({ + alias: activeCst.alias, + result: localParse ? localParse.typification : activeCst.parse.typification, + args: localParse ? localParse.args : activeCst.parse.args + }), + [activeCst, localParse] + ); const [forceComment, setForceComment] = useState(false); const isBasic = isBasicConcept(activeCst.cst_type); diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx index 664cc1b8..7d98bf12 100644 --- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx +++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSFormCard/FormRSForm.tsx @@ -1,11 +1,14 @@ +'use no memo'; // TODO: remove when react hook forms are compliant with react compiler 'use client'; +import { zodResolver } from '@hookform/resolvers/zod'; import clsx from 'clsx'; -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; +import { useForm, useWatch } from 'react-hook-form'; import { useConceptNavigation } from '@/app/Navigation/NavigationContext'; import { urls } from '@/app/urls'; -import { IUpdateLibraryItemDTO } from '@/backend/library/api'; +import { IUpdateLibraryItemDTO, UpdateLibraryItemSchema } from '@/backend/library/api'; import { useUpdateItem } from '@/backend/library/useUpdateItem'; import { useMutatingRSForm } from '@/backend/rsform/useMutatingRSForm'; import { IconSave } from '@/components/Icons'; @@ -28,106 +31,82 @@ interface FormRSFormProps { function FormRSForm({ id }: FormRSFormProps) { const controller = useRSEdit(); const router = useConceptNavigation(); - const schema = controller.schema; - const { updateItem: update } = useUpdateItem(); - const { isModified, setIsModified } = useModificationStore(); + const { updateItem: updateSchema } = useUpdateItem(); + const { setIsModified } = useModificationStore(); const isProcessing = useMutatingRSForm(); - const [title, setTitle] = useState(schema.title); - const [alias, setAlias] = useState(schema.alias); - const [comment, setComment] = useState(schema.comment); - const [visible, setVisible] = useState(schema.visible); - const [readOnly, setReadOnly] = useState(schema.read_only); + const { + register, + handleSubmit, + control, + setValue, + reset, + formState: { isDirty, errors } + } = useForm({ + resolver: zodResolver(UpdateLibraryItemSchema), + defaultValues: { + id: controller.schema.id, + item_type: LibraryItemType.RSFORM, + title: controller.schema.title, + alias: controller.schema.alias, + comment: controller.schema.comment, + visible: controller.schema.visible, + read_only: controller.schema.read_only + } + }); + const visible = useWatch({ control, name: 'visible' }); + const readOnly = useWatch({ control, name: 'read_only' }); + + useEffect(() => { + setIsModified(isDirty); + }, [isDirty, controller.schema, setIsModified]); function handleSelectVersion(version?: VersionID) { - router.push(urls.schema(schema.id, version)); + router.push(urls.schema(controller.schema.id, version)); } - useEffect(() => { - if (schema) { - setTitle(schema.title); - setAlias(schema.alias); - setComment(schema.comment); - setVisible(schema.visible); - setReadOnly(schema.read_only); - } - }, [schema]); - - useEffect(() => { - setIsModified( - schema.title !== title || - schema.alias !== alias || - schema.comment !== comment || - schema.visible !== visible || - schema.read_only !== readOnly - ); - return () => setIsModified(false); - }, [ - schema.title, - schema.alias, - schema.comment, - schema.visible, - schema.read_only, - title, - alias, - comment, - visible, - readOnly, - setIsModified - ]); - - const handleSubmit = (event?: React.FormEvent) => { - if (event) { - event.preventDefault(); - } - const data: IUpdateLibraryItemDTO = { - id: schema.id, - item_type: LibraryItemType.RSFORM, - title: title, - alias: alias, - comment: comment, - visible: visible, - read_only: readOnly - }; - update(data); - }; + function onSubmit(data: IUpdateLibraryItemDTO) { + updateSchema(data, () => reset({ ...data })); + } return ( -
+ void handleSubmit(onSubmit)(event)} + > setTitle(event.target.value)} + error={errors.title} />
setAlias(event.target.value)} + error={errors.alias} />
- 0} /> + 0} /> setVisible(prev => !prev)} + toggleVisible={() => setValue('visible', !visible, { shouldDirty: true })} readOnly={readOnly} - toggleReadOnly={() => setReadOnly(prev => !prev)} + toggleReadOnly={() => setValue('read_only', !readOnly, { shouldDirty: true })} controller={controller} />
@@ -135,18 +114,18 @@ function FormRSForm({ id }: FormRSFormProps) {