From eb378c2249fdcbc2d28a1b640ff7aa6bb7afadb4 Mon Sep 17 00:00:00 2001 From: Hendrik Schmidt Date: Fri, 27 Sep 2024 16:40:14 +0200 Subject: [PATCH] Refactor form validation Use answers from request in uniq --- .../app/routes/uniq.($encrypted).($iv).tsx | 4 +- .../vorpruefung.ergebnis/ResultForm.tsx | 71 +++++++++---------- 2 files changed, 34 insertions(+), 41 deletions(-) diff --git a/packages/dito/app/routes/uniq.($encrypted).($iv).tsx b/packages/dito/app/routes/uniq.($encrypted).($iv).tsx index 322a7a22..f3cd4131 100644 --- a/packages/dito/app/routes/uniq.($encrypted).($iv).tsx +++ b/packages/dito/app/routes/uniq.($encrypted).($iv).tsx @@ -3,7 +3,6 @@ import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto"; import { gunzipSync, gzipSync } from "node:zlib"; import { ROUTE_RESULT_PDF } from "resources/staticRoutes"; import { ENCRYPTION_ALGORITHM, ENCRYPTION_KEY } from "utils/constants.server"; -import { getAnswersFromCookie } from "utils/cookies.server"; import unleash from "utils/featureFlags.server"; enum QuestionAbbreviations { @@ -168,9 +167,8 @@ export async function action({ request }: ActionFunctionArgs) { "http://", process.env.NODE_ENV === "production" ? "https://" : "http://", ); - const { answers } = await getAnswersFromCookie(request); const formData = await request.formData(); - const { title, negativeReasoning } = Object.fromEntries(formData); + const { title, negativeReasoning, ...answers } = Object.fromEntries(formData); const combinedResponse = { title, diff --git a/packages/dito/app/routes/vorpruefung.ergebnis/ResultForm.tsx b/packages/dito/app/routes/vorpruefung.ergebnis/ResultForm.tsx index b83e9724..1bfdf7e7 100644 --- a/packages/dito/app/routes/vorpruefung.ergebnis/ResultForm.tsx +++ b/packages/dito/app/routes/vorpruefung.ergebnis/ResultForm.tsx @@ -7,7 +7,7 @@ import RichText from "@digitalcheck/shared/components/RichText"; import Textarea from "@digitalcheck/shared/components/Textarea"; import { useForm } from "@rvf/remix"; import { withZod } from "@rvf/zod"; -import React, { useEffect, useState } from "react"; +import React, { useState } from "react"; import { preCheck } from "resources/content"; import { PRE_CHECK_PDF, ROUTE_RESULT_PDF } from "resources/staticRoutes"; import { PreCheckAnswers } from "routes/vorpruefung.$questionId/route"; @@ -42,30 +42,38 @@ export default function ResultForm({ isPositive ? positiveValidation : negativeValidation, ); - const form = useForm({ - validator, - validationBehaviorConfig: { - initial: "onChange", - whenTouched: "onChange", - whenSubmitted: "onChange", - }, - }); + const form = useForm({ validator }); - const [downloadDisabled, setDownloadDisabled] = useState(false); - const downloadDocument = async () => { - setDownloadDisabled(true); + const validateFormAndGetData = async () => { + await form.validate(); + if (!form.transient.formState.isValid) { + return null; + } const formData = new FormData(); - formData.append("title", form.value("title")); - formData.append("negativeReasoning", form.value("negativeReasoning")); + // we need to use transient.value here because the form state is not yet updated + formData.append("title", form.transient.value("title") as string); + formData.append( + "negativeReasoning", + form.transient.value("negativeReasoning") as string, + ); Object.entries(answers).forEach(([key, value]) => { formData.append(key, value); }); + return formData; + }; + const [downloadDisabled, setDownloadDisabled] = useState(false); + const downloadDocument = async () => { + const formData = await validateFormAndGetData(); + if (!formData) { + return; + } + + setDownloadDisabled(true); const response = await fetch(ROUTE_RESULT_PDF.url, { method: "POST", body: formData, }); - if (!response.ok) { alert(`Error processing PDF: ${response.statusText}`); setDownloadDisabled(false); @@ -74,10 +82,9 @@ export default function ResultForm({ const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); - const a = document.createElement("a"); a.href = downloadUrl; - a.download = PRE_CHECK_PDF; + a.download = PRE_CHECK_PDF; // set filename document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(downloadUrl); @@ -86,18 +93,20 @@ export default function ResultForm({ }; const openMailTo = async () => { - const formData = new FormData(); - formData.append("title", form.value("title")); - formData.append("negativeReasoning", form.value("negativeReasoning")); + const formData = await validateFormAndGetData(); + if (!formData) { + return; + } const uniqueResponse = await fetch("/uniq", { method: "POST", body: formData, }); + const emailTemplate = preCheck.result.form.emailTemplate; const uniqueUrl = (await uniqueResponse.json()).url; - const subject = `${preCheck.result.form.emailTemplate.subject}: „${form.value("title")}“`; - const body = `${preCheck.result.form.emailTemplate.bodyBefore}\n\n${uniqueUrl}\n\n${preCheck.result.form.emailTemplate.bodyAfter}`; + const subject = `${emailTemplate.subject}: „${form.value("title")}“`; + const body = `${emailTemplate.bodyBefore}\n\n${uniqueUrl}\n\n${emailTemplate.bodyAfter}`; const mailToLink = encodeURI( - `mailto:${preCheck.result.form.emailTemplate.to}?subject=${subject}&body=${body}`, + `mailto:${emailTemplate.to}?subject=${subject}&body=${body}`, ); window.location.href = mailToLink; }; @@ -114,15 +123,6 @@ export default function ResultForm({ } }; - const [buttonsDisabled, setButtonsDisabled] = useState(false); - useEffect(() => { - // Workaround to call async validation in useEffect - void (async function () { - const result = await validator.validate(form.value()); - setButtonsDisabled(!!result.error); - })(); - }, [form, validator]); - return ( void openMailTo(), }, { @@ -183,8 +181,7 @@ export default function ResultForm({ ? preCheck.result.form.downloadStarted : preCheck.result.form.downloadPdfButton.text, look: "ghost", - disabled: buttonsDisabled || downloadDisabled, - type: "button", + disabled: downloadDisabled, onClick: () => void downloadDocument(), }, ] @@ -195,8 +192,6 @@ export default function ResultForm({ ? preCheck.result.form.downloadStarted : preCheck.result.form.downloadPdfButton.text, look: "primary", - disabled: buttonsDisabled || downloadDisabled, - type: "button", onClick: () => void downloadDocument(), }, ]