1
mirror of https://github.com/jakejarvis/jarv.is.git synced 2025-11-14 22:40:50 -05:00

use zod to validate form data the "right" way

This commit is contained in:
2025-03-05 12:49:54 -05:00
parent 8f946d50d8
commit b7977b8d96
6 changed files with 474 additions and 507 deletions

View File

@@ -5,7 +5,6 @@ import TextareaAutosize from "react-textarea-autosize";
import Turnstile from "react-turnstile";
import clsx from "clsx";
import Link from "../../components/Link";
import useTheme from "../../hooks/useTheme";
import { sendMessage } from "./actions";
import { GoCheck, GoX } from "react-icons/go";
import { SiMarkdown } from "react-icons/si";
@@ -13,11 +12,10 @@ import { SiMarkdown } from "react-icons/si";
import styles from "./form.module.css";
const ContactForm = () => {
const { theme } = useTheme();
const [formState, formAction, pending] = useActionState<
Partial<{ success: boolean; message: string; payload: FormData }>,
FormData
>(sendMessage, {});
const [formState, formAction, pending] = useActionState<Partial<Awaited<ReturnType<typeof sendMessage>>>, FormData>(
sendMessage,
{}
);
return (
<form action={formAction}>
@@ -26,7 +24,7 @@ const ContactForm = () => {
name="name"
placeholder="Name"
required
className={styles.input}
className={clsx(styles.input, formState?.errors?.name && styles.invalid)}
defaultValue={(formState?.payload?.get("name") || "") as string}
disabled={formState?.success}
/>
@@ -37,7 +35,7 @@ const ContactForm = () => {
placeholder="Email"
required
inputMode="email"
className={styles.input}
className={clsx(styles.input, formState?.errors?.email && styles.invalid)}
defaultValue={(formState?.payload?.get("email") || "") as string}
disabled={formState?.success}
/>
@@ -47,7 +45,7 @@ const ContactForm = () => {
placeholder="Write something..."
minRows={5}
required
className={styles.input}
className={clsx(styles.input, styles.textarea, formState?.errors?.message && styles.invalid)}
defaultValue={(formState?.payload?.get("message") || "") as string}
disabled={formState?.success}
/>
@@ -78,12 +76,9 @@ const ContactForm = () => {
](https://jarv.is), and <code>`code`</code>.
</div>
<Turnstile
sitekey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY || "1x00000000000000000000AA"}
style={{ margin: "1em 0" }}
theme={theme === "dark" ? theme : "light"}
fixedSize
/>
<div style={{ margin: "1em 0" }}>
<Turnstile sitekey={process.env.NEXT_PUBLIC_TURNSTILE_SITE_KEY || "1x00000000000000000000AA"} fixedSize />
</div>
<div className={styles.actionRow}>
{!formState?.success && (