From 90f94593142daae59a4613813742f1dde984b2e5 Mon Sep 17 00:00:00 2001 From: Sofi Bel <91890402+sofi-bel@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:14:17 +0400 Subject: [PATCH] fix(post-form): Review form bugs: comments, recommend-to, checkbox --- client/graphql/gql-tada/graphql-env.d.ts | 2 +- .../apps/reviews/create/PostReviewForm.tsx | 50 ++---------- client/src/apps/users/useUserCurrent.ts | 1 + .../forms/FormChakraCheckboxCard.tsx | 8 +- .../components/posts/form/SelectVotable.tsx | 55 +++++++++++-- .../components/posts/form/ToolAsyncSelect.tsx | 1 + client/src/components/posts/form/schemas.ts | 81 ++++++++++++++++--- client/src/utils/useInit.ts | 1 + schema.graphql | 1 + server/neuronhub/apps/posts/graphql/types.py | 1 + .../posts/services/post_update_or_create.py | 8 +- .../services/post_update_or_create__test.py | 38 +++++++++ server/persisted-queries.json | 4 +- 13 files changed, 182 insertions(+), 69 deletions(-) diff --git a/client/graphql/gql-tada/graphql-env.d.ts b/client/graphql/gql-tada/graphql-env.d.ts index 2e34ed8a..012b1eef 100644 --- a/client/graphql/gql-tada/graphql-env.d.ts +++ b/client/graphql/gql-tada/graphql-env.d.ts @@ -59,7 +59,7 @@ export type introspection_types = { 'PostTagFilter': { kind: 'INPUT_OBJECT'; name: 'PostTagFilter'; isOneOf: false; inputFields: [{ name: 'id'; type: { kind: 'INPUT_OBJECT'; name: 'IDBaseFilterLookup'; ofType: null; }; defaultValue: null }, { name: 'name'; type: { kind: 'INPUT_OBJECT'; name: 'StrFilterLookup'; ofType: null; }; defaultValue: null }, { name: 'description'; type: { kind: 'INPUT_OBJECT'; name: 'StrFilterLookup'; ofType: null; }; defaultValue: null }, { name: 'is_review_tag'; type: { kind: 'INPUT_OBJECT'; name: 'BoolBaseFilterLookup'; ofType: null; }; defaultValue: null }, { name: 'categories'; type: { kind: 'INPUT_OBJECT'; name: 'PostTagCategoryFilter'; ofType: null; }; defaultValue: null }, { name: 'AND'; type: { kind: 'INPUT_OBJECT'; name: 'PostTagFilter'; ofType: null; }; defaultValue: null }, { name: 'OR'; type: { kind: 'INPUT_OBJECT'; name: 'PostTagFilter'; ofType: null; }; defaultValue: null }, { name: 'NOT'; type: { kind: 'INPUT_OBJECT'; name: 'PostTagFilter'; ofType: null; }; defaultValue: null }, { name: 'DISTINCT'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }]; }; 'PostTagType': { kind: 'OBJECT'; name: 'PostTagType'; fields: { 'aliases': { name: 'aliases'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; }; } }; 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'UserType'; ofType: null; } }; 'category_name': { name: 'category_name'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; } }; 'description': { name: 'description'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'is_important': { name: 'is_important'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; } }; 'is_review_tag': { name: 'is_review_tag'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; 'label': { name: 'label'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'name': { name: 'name'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'posts': { name: 'posts'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostType'; ofType: null; }; }; }; } }; 'tag_children': { name: 'tag_children'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; }; }; }; } }; 'tag_parent': { name: 'tag_parent'; type: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; } }; 'votes': { name: 'votes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagVoteType'; ofType: null; }; }; }; } }; }; }; 'PostTagTypeInput': { kind: 'INPUT_OBJECT'; name: 'PostTagTypeInput'; isOneOf: false; inputFields: [{ name: 'name'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; }; defaultValue: null }, { name: 'id'; type: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; defaultValue: null }, { name: 'comment'; type: { kind: 'SCALAR'; name: 'String'; ofType: null; }; defaultValue: null }, { name: 'is_review_tag'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }, { name: 'is_vote_positive'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }, { name: 'is_important'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; defaultValue: null }, { name: 'tag_parent'; type: { kind: 'INPUT_OBJECT'; name: 'PostTagTypeInput'; ofType: null; }; defaultValue: null }]; }; - 'PostTagVoteType': { kind: 'OBJECT'; name: 'PostTagVoteType'; fields: { 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'UserType'; ofType: null; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'is_changed_my_mind': { name: 'is_changed_my_mind'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; 'is_vote_positive': { name: 'is_vote_positive'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; } }; 'post': { name: 'post'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostSimpleType'; ofType: null; }; } }; 'tag': { name: 'tag'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; }; } }; }; }; + 'PostTagVoteType': { kind: 'OBJECT'; name: 'PostTagVoteType'; fields: { 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'UserType'; ofType: null; } }; 'comment': { name: 'comment'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'is_changed_my_mind': { name: 'is_changed_my_mind'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; }; } }; 'is_vote_positive': { name: 'is_vote_positive'; type: { kind: 'SCALAR'; name: 'Boolean'; ofType: null; } }; 'post': { name: 'post'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostSimpleType'; ofType: null; }; } }; 'tag': { name: 'tag'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; }; } }; }; }; 'PostToolType': { kind: 'OBJECT'; name: 'PostToolType'; fields: { 'TYPE': { name: 'TYPE'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'PostTypeEnum'; ofType: null; }; } }; 'alternatives': { name: 'alternatives'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostToolType'; ofType: null; }; }; }; } }; 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'UserType'; ofType: null; } }; 'category': { name: 'category'; type: { kind: 'ENUM'; name: 'PostCategory'; ofType: null; } }; 'children': { name: 'children'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; }; }; }; } }; 'comment_count': { name: 'comment_count'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'comments': { name: 'comments'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostCommentType'; ofType: null; }; }; }; } }; 'company': { name: 'company'; type: { kind: 'OBJECT'; name: 'DjangoModelType'; ofType: null; } }; 'content_direct': { name: 'content_direct'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_polite': { name: 'content_polite'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_polite_html_ssr': { name: 'content_polite_html_ssr'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_private': { name: 'content_private'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_rant': { name: 'content_rant'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'created_at': { name: 'created_at'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; } }; 'crunchbase_url': { name: 'crunchbase_url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'domain': { name: 'domain'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'github_url': { name: 'github_url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'image': { name: 'image'; type: { kind: 'OBJECT'; name: 'DjangoImageType'; ofType: null; } }; 'parent': { name: 'parent'; type: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; } }; 'parent_root': { name: 'parent_root'; type: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; } }; 'post_source': { name: 'post_source'; type: { kind: 'OBJECT'; name: 'PostSourceType'; ofType: null; } }; 'recommended_to_groups': { name: 'recommended_to_groups'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserConnectionGroupType'; ofType: null; }; }; }; } }; 'recommended_to_users': { name: 'recommended_to_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserType'; ofType: null; }; }; }; } }; 'seen_by_users': { name: 'seen_by_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DjangoModelType'; ofType: null; }; }; }; } }; 'source': { name: 'source'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'source_author': { name: 'source_author'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'tag_votes': { name: 'tag_votes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagVoteType'; ofType: null; }; }; }; } }; 'tags': { name: 'tags'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; }; }; }; } }; 'title': { name: 'title'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'tool_type': { name: 'tool_type'; type: { kind: 'ENUM'; name: 'ToolType'; ofType: null; } }; 'type': { name: 'type'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'PostTypeEnum'; ofType: null; }; } }; 'updated_at': { name: 'updated_at'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; } }; 'url': { name: 'url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'visibility': { name: 'visibility'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'Visibility'; ofType: null; }; } }; 'visible_to_groups': { name: 'visible_to_groups'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserConnectionGroupType'; ofType: null; }; }; }; } }; 'visible_to_users': { name: 'visible_to_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserType'; ofType: null; }; }; }; } }; 'votes': { name: 'votes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostVoteType'; ofType: null; }; }; }; } }; }; }; 'PostType': { kind: 'OBJECT'; name: 'PostType'; fields: { 'TYPE': { name: 'TYPE'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'PostTypeEnum'; ofType: null; }; } }; 'author': { name: 'author'; type: { kind: 'OBJECT'; name: 'UserType'; ofType: null; } }; 'category': { name: 'category'; type: { kind: 'ENUM'; name: 'PostCategory'; ofType: null; } }; 'children': { name: 'children'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; }; }; }; } }; 'comment_count': { name: 'comment_count'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'Int'; ofType: null; }; } }; 'comments': { name: 'comments'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostCommentType'; ofType: null; }; }; }; } }; 'company': { name: 'company'; type: { kind: 'OBJECT'; name: 'DjangoModelType'; ofType: null; } }; 'content_direct': { name: 'content_direct'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_polite': { name: 'content_polite'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_polite_html_ssr': { name: 'content_polite_html_ssr'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_private': { name: 'content_private'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'content_rant': { name: 'content_rant'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'created_at': { name: 'created_at'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; } }; 'crunchbase_url': { name: 'crunchbase_url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'domain': { name: 'domain'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'github_url': { name: 'github_url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'id': { name: 'id'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'ID'; ofType: null; }; } }; 'image': { name: 'image'; type: { kind: 'OBJECT'; name: 'DjangoImageType'; ofType: null; } }; 'parent': { name: 'parent'; type: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; } }; 'parent_root': { name: 'parent_root'; type: { kind: 'INTERFACE'; name: 'PostTypeI'; ofType: null; } }; 'post_source': { name: 'post_source'; type: { kind: 'OBJECT'; name: 'PostSourceType'; ofType: null; } }; 'recommended_to_groups': { name: 'recommended_to_groups'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserConnectionGroupType'; ofType: null; }; }; }; } }; 'recommended_to_users': { name: 'recommended_to_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserType'; ofType: null; }; }; }; } }; 'seen_by_users': { name: 'seen_by_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'DjangoModelType'; ofType: null; }; }; }; } }; 'source': { name: 'source'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'source_author': { name: 'source_author'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'tag_votes': { name: 'tag_votes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagVoteType'; ofType: null; }; }; }; } }; 'tags': { name: 'tags'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostTagType'; ofType: null; }; }; }; } }; 'title': { name: 'title'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'tool_type': { name: 'tool_type'; type: { kind: 'ENUM'; name: 'ToolType'; ofType: null; } }; 'type': { name: 'type'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'PostTypeEnum'; ofType: null; }; } }; 'updated_at': { name: 'updated_at'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'DateTime'; ofType: null; }; } }; 'url': { name: 'url'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'SCALAR'; name: 'String'; ofType: null; }; } }; 'visibility': { name: 'visibility'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'ENUM'; name: 'Visibility'; ofType: null; }; } }; 'visible_to_groups': { name: 'visible_to_groups'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserConnectionGroupType'; ofType: null; }; }; }; } }; 'visible_to_users': { name: 'visible_to_users'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'UserType'; ofType: null; }; }; }; } }; 'votes': { name: 'votes'; type: { kind: 'NON_NULL'; name: never; ofType: { kind: 'LIST'; name: never; ofType: { kind: 'NON_NULL'; name: never; ofType: { kind: 'OBJECT'; name: 'PostVoteType'; ofType: null; }; }; }; } }; }; }; 'PostTypeEnum': { name: 'PostTypeEnum'; enumValues: 'Post' | 'Tool' | 'Review' | 'Comment'; }; diff --git a/client/src/apps/reviews/create/PostReviewForm.tsx b/client/src/apps/reviews/create/PostReviewForm.tsx index 6060a8b2..77f585c2 100644 --- a/client/src/apps/reviews/create/PostReviewForm.tsx +++ b/client/src/apps/reviews/create/PostReviewForm.tsx @@ -39,41 +39,28 @@ export namespace PostReviewForm { const user = useUser(); const loading = useIsLoading(); - // todo refac(UX): fix broken `reValidateMode: "onChange"` - after refactor to 2 forms validates only on