From d250418d00530016549d4884be1959c47a0bd613 Mon Sep 17 00:00:00 2001 From: Victor Zeinstra Date: Mon, 9 Oct 2023 18:58:17 +0200 Subject: [PATCH] refactor: contrib zod type (#1074) * refactor: make form specific types * fix: updateDate * chore: clean * chore: clean --------- Co-authored-by: Victor Zeinstra --- .../contributions/answers/AnswerForm.tsx | 79 +++++++++++++++---- .../questions/EditQuestionForm.tsx | 14 ++-- .../questions/Question.mutation.ts | 2 +- .../src/components/contributions/type.ts | 76 +++--------------- 4 files changed, 84 insertions(+), 87 deletions(-) diff --git a/targets/frontend/src/components/contributions/answers/AnswerForm.tsx b/targets/frontend/src/components/contributions/answers/AnswerForm.tsx index 08d078216..c203bc7d2 100644 --- a/targets/frontend/src/components/contributions/answers/AnswerForm.tsx +++ b/targets/frontend/src/components/contributions/answers/AnswerForm.tsx @@ -2,9 +2,10 @@ import { Button, FormControl, Stack } from "@mui/material"; import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; import { FormEditionField, FormRadioGroup, FormTextField } from "../../forms"; -import { Answer, Status, answerFormSchema } from "../type"; +import { Answer, Status, answerRelationSchema, documentSchema } from "../type"; import { AnswerWithStatus } from "./answer.query"; import { CdtnReferenceInput, @@ -15,6 +16,55 @@ import { import { getNextStatus, getPrimaryButtonLabel } from "../status/utils"; import { FicheSpDocumentInput } from "./references/FicheSpDocumentInput"; +const answerFormBaseSchema = answerRelationSchema + .pick({ + content: true, + contentType: true, + cdtnReferences: true, + kaliReferences: true, + legiReferences: true, + otherReferences: true, + contentFichesSpDocument: true, + }) + .extend({ + updateDate: z.string(), + }); +const answerWithAnswerSchema = answerFormBaseSchema.extend({ + contentType: z.literal("ANSWER"), + content: z + .string({ + required_error: "Une réponse doit être renseigner", + invalid_type_error: "Une réponse doit être renseigner", + }) + .min(1, "Une réponse doit être renseigner"), +}); +const answerWithNothingSchema = answerFormBaseSchema.extend({ + contentType: z.literal("NOTHING"), +}); +const answerWithCdtSchema = answerFormBaseSchema.extend({ + contentType: z.literal("CDT"), +}); +const answerWithUnfavourableSchema = answerFormBaseSchema.extend({ + contentType: z.literal("UNFAVOURABLE"), +}); +const answerWithUnknownSchema = answerFormBaseSchema.extend({ + contentType: z.literal("UNKNOWN"), +}); +const answerWithSPSchema = answerFormBaseSchema.extend({ + contentType: z.literal("SP"), + contentFichesSpDocument: documentSchema, +}); + +export const answerFormSchema = z.discriminatedUnion("contentType", [ + answerWithAnswerSchema, + answerWithNothingSchema, + answerWithCdtSchema, + answerWithUnfavourableSchema, + answerWithUnknownSchema, + answerWithSPSchema, +]); +export type AnswerFormValidation = z.infer; + export type ContributionsAnswerProps = { answer: AnswerWithStatus; onSubmit: (status: Status, data: Answer) => void; @@ -38,20 +88,18 @@ export const AnswerForm = ({ setStatus(answer.status.status); } }, [answer]); - const { control, getValues, trigger } = useForm({ + const { control, getValues, trigger } = useForm({ resolver: zodResolver(answerFormSchema), shouldFocusError: true, defaultValues: { - content: "", - contentType: "ANSWER", - status: { - status: "TODO", - }, - legiReferences: [], - kaliReferences: [], - otherReferences: [], - cdtnReferences: [], - contentFichesSpDocument: answer?.contentFichesSpDocument ? {} : undefined, + content: answer?.content ?? "", + contentType: answer?.contentType ?? "ANSWER", + legiReferences: answer?.legiReferences ?? [], + kaliReferences: answer?.kaliReferences ?? [], + otherReferences: answer?.otherReferences ?? [], + cdtnReferences: answer?.cdtnReferences ?? [], + contentFichesSpDocument: answer?.contentFichesSpDocument ?? undefined, + updateDate: answer?.updateDate ?? "", }, }); @@ -60,8 +108,11 @@ export const AnswerForm = ({ if (isValid) { setStatus(newStatus); - const data = getValues(); - onSubmit(newStatus, data); + const formData = getValues(); + onSubmit(newStatus, { + ...answer, + ...formData, + }); } }; diff --git a/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx b/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx index 43256ed48..3817c2875 100644 --- a/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx +++ b/targets/frontend/src/components/contributions/questions/EditQuestionForm.tsx @@ -14,12 +14,9 @@ type EditQuestionProps = { messages: Message[]; }; -const formDataSchema = questionRelationSchema.extend({ - message_id: z - .string({ - required_error: "Un message doit être sélectionné", - }) - .uuid("Un message doit être sélectionné"), +const formDataSchema = questionRelationSchema.pick({ + message_id: true, + content: true, }); export type FormData = z.infer; @@ -32,7 +29,6 @@ export const EditQuestionForm = ({ shouldFocusError: true, defaultValues: { content: question.content, - id: question.id, message_id: question.message?.id ?? "", }, }); @@ -57,9 +53,9 @@ export const EditQuestionForm = ({ } }, [watchMessageId, messages]); - const onSubmit = async (data: FormData) => { + const onSubmit = async (formData: FormData) => { try { - const result = await updateQuestion(data); + const result = await updateQuestion({ id: question.id, ...formData }); if (result.error) { setSnack({ message: `Erreur: ${result.error.message}`, diff --git a/targets/frontend/src/components/contributions/questions/Question.mutation.ts b/targets/frontend/src/components/contributions/questions/Question.mutation.ts index cdb0dddd9..059387544 100644 --- a/targets/frontend/src/components/contributions/questions/Question.mutation.ts +++ b/targets/frontend/src/components/contributions/questions/Question.mutation.ts @@ -10,7 +10,7 @@ mutation contributionQuestionUpdate($id: uuid!, $content: String, $message_id: u } `; -type MutationProps = Question; +type MutationProps = Pick; type MutationResult = (props: MutationProps) => Promise; diff --git a/targets/frontend/src/components/contributions/type.ts b/targets/frontend/src/components/contributions/type.ts index 7c45ff629..b7368f3ba 100644 --- a/targets/frontend/src/components/contributions/type.ts +++ b/targets/frontend/src/components/contributions/type.ts @@ -102,24 +102,17 @@ export const cdtnReferenceSchema = z.object({ }); export type CdtnReference = z.infer; -export const contentTypeSchema = z.enum([ - "ANSWER", - "NOTHING", - "CDT", - "UNFAVOURABLE", - "UNKNOWN", - "SP", -]); -export type ContentType = z.infer; - const answerBaseSchema = z.object({ id: z.string().uuid(), agreementId: z.string(), questionId: z.string().uuid(), - contentType: z.string({ - required_error: "Un type de réponse doit être sélectionner", - invalid_type_error: " type de réponse doit être sélectionner", - }), + contentType: z.enum( + ["ANSWER", "NOTHING", "CDT", "UNFAVOURABLE", "UNKNOWN", "SP"], + { + required_error: "Un type de réponse doit être sélectionner", + invalid_type_error: " type de réponse doit être sélectionner", + } + ), contentServicePublicCdtnId: z.string().nullable().optional(), content: z.string().nullable().optional(), updatedAt: z.string(), @@ -133,6 +126,11 @@ export const questionBaseSchema = z.object({ }) .min(1, "une question doit être renseigner"), order: z.number(), + message_id: z + .string({ + required_error: "Un message doit être sélectionné", + }) + .uuid("Un message doit être sélectionné"), }); export const commentsSchema = z.object({ @@ -146,7 +144,7 @@ export const commentsSchema = z.object({ }); export type Comments = z.infer; -const answerRelationSchema = answerBaseSchema.extend({ +export const answerRelationSchema = answerBaseSchema.extend({ agreement: agreementSchema, statuses: z.array(answerStatusSchema), status: answerStatusSchema, @@ -160,56 +158,8 @@ const answerRelationSchema = answerBaseSchema.extend({ }); export type Answer = z.infer; -export const answerFormBaseSchema = answerRelationSchema.extend({ - id: z.string().uuid().optional(), - agreementId: z.string().optional(), - questionId: z.string().uuid().optional(), - updatedAt: z.string().optional(), - question: questionBaseSchema.deepPartial().optional(), - answerComments: z.array(commentsSchema.deepPartial()).optional(), - agreement: agreementSchema.deepPartial().optional(), - statuses: z.array(answerStatusSchema.deepPartial()).optional(), - status: answerStatusSchema.deepPartial().optional(), -}); - export const questionRelationSchema = questionBaseSchema.extend({ answers: z.array(answerBaseSchema.deepPartial()).optional(), message: messageSchema.deepPartial().optional(), }); export type Question = z.infer; - -const answerWithAnswerSchema = answerFormBaseSchema.extend({ - contentType: z.literal("ANSWER"), - content: z - .string({ - required_error: "Une réponse doit être renseigner", - invalid_type_error: "Une réponse doit être renseigner", - }) - .min(1, "Une réponse doit être renseigner"), -}); -const answerWithNothingSchema = answerFormBaseSchema.extend({ - contentType: z.literal("NOTHING"), -}); -const answerWithCdtSchema = answerFormBaseSchema.extend({ - contentType: z.literal("CDT"), -}); -const answerWithUnfavourableSchema = answerFormBaseSchema.extend({ - contentType: z.literal("UNFAVOURABLE"), -}); -const answerWithUnknownSchema = answerFormBaseSchema.extend({ - contentType: z.literal("UNKNOWN"), -}); -const answerWithSPSchema = answerFormBaseSchema.extend({ - contentType: z.literal("SP"), - contentFichesSpDocument: documentSchema, -}); - -export const answerFormSchema = z.discriminatedUnion("contentType", [ - answerWithAnswerSchema, - answerWithNothingSchema, - answerWithCdtSchema, - answerWithUnfavourableSchema, - answerWithUnknownSchema, - answerWithSPSchema, -]); -export type AnswerForm = z.infer;