added form validation to regions form.
All checks were successful
Vercel Production Deployment / Deploy-Production (push) Successful in 1m31s
All checks were successful
Vercel Production Deployment / Deploy-Production (push) Successful in 1m31s
This commit is contained in:
parent
4f5a9c429c
commit
f0125fd472
@ -1,11 +1,12 @@
|
|||||||
import { useFormStatus } from "react-dom";
|
import { useFormStatus } from "react-dom";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
|
|
||||||
export default function SubmitButton() {
|
export default function SubmitButton(props: { text: string }) {
|
||||||
|
const { text } = props;
|
||||||
const { pending } = useFormStatus();
|
const { pending } = useFormStatus();
|
||||||
return (
|
return (
|
||||||
<Button disabled={pending}>
|
<Button disabled={pending}>
|
||||||
{pending ? "Adding country.." : "Add country"}
|
{pending ? `Adding ${text}` : `Add ${text}`}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Input } from "~/components/ui/input";
|
import { Input } from "~/components/ui/input";
|
||||||
import { addCountry } from "~/server/actions/createCountry";
|
import { addCountry } from "~/server/actions/addCountry";
|
||||||
import SubmitButton from "../SubmitButton";
|
import SubmitButton from "../SubmitButton";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
|
|
||||||
@ -17,7 +17,7 @@ export default function CreateCountryForm() {
|
|||||||
return (
|
return (
|
||||||
<form ref={ref} action={handleSubmit}>
|
<form ref={ref} action={handleSubmit}>
|
||||||
<Input name="name" required />
|
<Input name="name" required />
|
||||||
<SubmitButton />
|
<SubmitButton text={"Country"} />
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import { Input } from "~/components/ui/input";
|
import { Input } from "~/components/ui/input";
|
||||||
import SubmitButton from "../SubmitButton";
|
import SubmitButton from "../SubmitButton";
|
||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { addRegion } from "~/server/actions/createRegion";
|
import { addRegion } from "~/server/actions/addRegion";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
SelectContent,
|
SelectContent,
|
||||||
@ -10,21 +10,20 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "~/components/ui/select";
|
} from "~/components/ui/select";
|
||||||
|
import { useFormState } from "react-dom";
|
||||||
|
import { init } from "next/dist/compiled/webpack/webpack";
|
||||||
|
|
||||||
type Country = {
|
interface Country {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function CreateRegionForm(props: { countries: Country[] }) {
|
export default function CreateRegionForm(props: { countries: Country[] }) {
|
||||||
|
const [state, formAction] = useFormState(addRegion, null);
|
||||||
const { countries } = props;
|
const { countries } = props;
|
||||||
const ref = useRef<HTMLFormElement>(null);
|
const ref = useRef<HTMLFormElement>(null);
|
||||||
const handleSubmit = async (formData: FormData) => {
|
|
||||||
ref.current?.reset();
|
|
||||||
await addRegion(formData);
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<form ref={ref} action={handleSubmit}>
|
<form ref={ref} action={formAction}>
|
||||||
<Input name="name" required />
|
<Input name="name" required />
|
||||||
<Select name="country">
|
<Select name="country">
|
||||||
<SelectTrigger className="w-[180px]">
|
<SelectTrigger className="w-[180px]">
|
||||||
@ -38,8 +37,8 @@ export default function CreateRegionForm(props: { countries: Country[] }) {
|
|||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
<SubmitButton text={"Region"} />
|
||||||
<SubmitButton />
|
<span>{state?.message}</span>
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
"use client";
|
|
||||||
import { Input } from "~/components/ui/input";
|
|
||||||
import { addCountry } from "~/server/actions/createCountry";
|
|
||||||
import SubmitButton from "../SubmitButton";
|
|
||||||
import { useRef } from "react";
|
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "~/components/ui/select";
|
|
||||||
|
|
||||||
export default function CreateCountryForm() {
|
|
||||||
const ref = useRef<HTMLFormElement>(null);
|
|
||||||
const handleSubmit = async (formData: FormData) => {
|
|
||||||
ref.current?.reset();
|
|
||||||
await addCountry(formData);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<form ref={ref} action={handleSubmit}>
|
|
||||||
<Input name="name" required />
|
|
||||||
<Select>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue placeholder="Wine type" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="light">Light</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<SubmitButton />
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
}
|
|
43
src/server/actions/addRegion.ts
Normal file
43
src/server/actions/addRegion.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
"use server";
|
||||||
|
|
||||||
|
import { revalidatePath } from "next/cache";
|
||||||
|
import { db } from "../db";
|
||||||
|
import { regions } from "../db/schema";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
countryId: z.string().min(1, "No country selected"),
|
||||||
|
name: z.string().min(1, "Name is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const addRegion = async (prevstate: any, formData: FormData) => {
|
||||||
|
const newRegion = schema.safeParse({
|
||||||
|
name: (formData.get("name") as string).toLowerCase(),
|
||||||
|
countryId: formData.get("country") as string,
|
||||||
|
});
|
||||||
|
if (!newRegion.success) {
|
||||||
|
return {
|
||||||
|
message: "failed",
|
||||||
|
errors: newRegion.error,
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const confirmedRegion = await db
|
||||||
|
.insert(regions)
|
||||||
|
.values(newRegion.data)
|
||||||
|
.onConflictDoNothing({ target: regions.name })
|
||||||
|
.returning({ name: regions.name });
|
||||||
|
if (!confirmedRegion[0]?.name) {
|
||||||
|
return {
|
||||||
|
message: "region already exists",
|
||||||
|
errors: newRegion.error,
|
||||||
|
data: null,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const message = `${newRegion.data.name} added`;
|
||||||
|
const errors = newRegion.error;
|
||||||
|
const data = newRegion.data;
|
||||||
|
revalidatePath("/");
|
||||||
|
return { message, errors, data };
|
||||||
|
}
|
||||||
|
};
|
@ -1,30 +0,0 @@
|
|||||||
"use server";
|
|
||||||
|
|
||||||
import { revalidatePath } from "next/cache";
|
|
||||||
import { db } from "../db";
|
|
||||||
import { regions } from "../db/schema";
|
|
||||||
import { z } from "zod";
|
|
||||||
|
|
||||||
type NewRegion = {
|
|
||||||
name: string;
|
|
||||||
countryId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const schema = z.object({
|
|
||||||
countryId: z.string(),
|
|
||||||
name: z.string().min(1, "Name is required"),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const addRegion = async (formData: FormData) => {
|
|
||||||
const newRegion: NewRegion = {
|
|
||||||
name: (formData.get("name") as string).toLowerCase(),
|
|
||||||
countryId: formData.get("country") as string,
|
|
||||||
};
|
|
||||||
revalidatePath("/");
|
|
||||||
await db.insert(regions).values(newRegion).returning();
|
|
||||||
return {
|
|
||||||
message: message,
|
|
||||||
errors: error,
|
|
||||||
status: 200,
|
|
||||||
};
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user