diff --git a/bun.lockb b/bun.lockb index 329b82b..1be75e3 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 53f2d95..0cc0b8f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@heroicons/react": "^2.0.18", - "@hookform/resolvers": "^3.2.0", + "@hookform/resolvers": "^3.9.1", "@marsidev/react-turnstile": "^0.5.3", "@next/bundle-analyzer": "^14.0.4", "@planetscale/database": "^1.10.0", @@ -64,8 +64,8 @@ "tailwindcss": "3.3.2", "tailwindcss-animate": "^1.0.6", "typescript": "5.1.6", - "valibot": "^0.42.1", - "vaul": "^0.8.0" + "vaul": "^0.8.0", + "zod": "^3.23.8" }, "devDependencies": { "drizzle-kit": "^0.22.7", diff --git a/src/pages/editor/create.tsx b/src/pages/editor/create.tsx index c0520e8..c2cb065 100644 --- a/src/pages/editor/create.tsx +++ b/src/pages/editor/create.tsx @@ -3,10 +3,10 @@ import { useRouter } from "next/router"; import type { PlayerType } from "@/contexts/players-context"; -import { valibotResolver } from "@hookform/resolvers/valibot"; +import { zodResolver } from "@hookform/resolvers/zod"; import { useState } from "react"; import { useForm } from "react-hook-form"; -import * as v from "valibot"; +import * as z from "zod"; import { usePlayers } from "@/contexts/players-context"; @@ -48,82 +48,35 @@ function generateUniqueIdentifier() { return uniqueIdentifier.substring(0, 32); } -const formSchema = v.object({ - name: v.pipe( - v.string(), - v.minLength(1, "Please enter your farm name!"), - v.maxLength(32, "Name must be 32 characters or less"), - v.trim(), - ), - gameVersion: v.string(), - questsCompleted: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(100_000), - v.transform((v) => Number(v)), - ), - ), - farmName: v.pipe( - v.string(), - v.minLength(1, "Please enter your farm name!"), - v.maxLength(32, "Name must be 32 characters or less"), - v.trim(), - ), - farmType: v.pipe( - v.string(), - v.minLength(1, "Please select a farm type!"), - v.maxLength(32), - v.trim(), - ), - totalMoneyEarned: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(1_000_000_000), - v.transform((v) => Number(v)), - ), - 0, - ), - fishCaught: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(100000), - v.transform((v) => Number(v)), - ), - ), - numObelisks: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(4), - v.transform((v) => Number(v)), - ), - ), - goldenClock: v.optional(v.boolean()), - childrenCount: v.optional( - v.pipe( - v.number(), - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(2), - ), - ), - houseUpgradeLevel: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(3), - v.transform((v) => Number(v)), - ), - ), - farming: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(10))), - fishing: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(10))), - foraging: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(10))), - mining: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(10))), - combat: v.optional(v.pipe(v.number(), v.minValue(0), v.maxValue(10))), +export const formSchema = z.object({ + name: z + .string() + .min(1, { message: "Please enter your farm name!" }) + .max(32, { message: "Name must be 32 characters or less" }) + .trim(), + gameVersion: z.string(), + questsCompleted: z.coerce.number().min(0).max(100_000).optional(), + farmName: z + .string() + .min(1, { message: "Please enter your farm name!" }) + .max(32, { message: "Name must be 32 characters or less" }) + .trim(), + farmType: z + .string() + .min(1, { message: "Please select a farm type!" }) + .max(32) + .trim(), + totalMoneyEarned: z.coerce.number().min(0).max(1_000_000_000).default(0), + fishCaught: z.coerce.number().min(0).max(100_000).optional(), + numObelisks: z.coerce.number().min(0).max(4).optional(), + goldenClock: z.boolean().optional(), + childrenCount: z.coerce.number().min(0).max(2).optional(), + houseUpgradeLevel: z.coerce.number().min(0).max(3).optional(), + farming: z.coerce.number().min(0).max(10).optional(), + fishing: z.coerce.number().min(0).max(10).optional(), + foraging: z.coerce.number().min(0).max(10).optional(), + mining: z.coerce.number().min(0).max(10).optional(), + combat: z.coerce.number().min(0).max(10).optional(), }); export const skillsArray = [ @@ -142,7 +95,7 @@ export default function Editor() { const [isExpanded, setIsExpanded] = useState(false); const form = useForm({ - resolver: valibotResolver(formSchema), + resolver: zodResolver(formSchema), defaultValues: { name: "", gameVersion: "", @@ -163,7 +116,7 @@ export default function Editor() { }, }); - const onSubmit = async (values: v.InferInput) => { + const onSubmit = async (values: z.infer) => { setDisabled(true); const player: PlayerType = { _id: generateUniqueIdentifier(), diff --git a/src/pages/editor/edit.tsx b/src/pages/editor/edit.tsx index 0610224..0fea553 100644 --- a/src/pages/editor/edit.tsx +++ b/src/pages/editor/edit.tsx @@ -3,10 +3,10 @@ import Link from "next/link"; import type { PlayerType } from "@/contexts/players-context"; -import { valibotResolver } from "@hookform/resolvers/valibot"; +import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useMemo, useState } from "react"; import { useForm } from "react-hook-form"; -import * as v from "valibot"; +import * as z from "zod"; import { usePlayers } from "@/contexts/players-context"; @@ -38,118 +38,7 @@ import { } from "@/components/ui/select"; import { Switch } from "@/components/ui/switch"; import { toast } from "sonner"; - -const formSchema = v.object({ - name: v.pipe( - v.string(), - v.minLength(1), - v.maxLength(32, "Name must be 32 characters or less"), - v.trim(), - ), - gameVersion: v.string(), - questsCompleted: v.optional( - v.pipe( - v.union([v.string(), v.number()]), - v.minValue(0), - v.maxValue(100000), - v.transform((v) => Number(v)), - ), - ), - farmName: v.pipe( - v.string(), - v.minLength(1), - v.maxLength(32, "Name must be 32 characters or less"), - v.trim(), - ), - farmType: v.pipe(v.string(), v.minLength(1), v.maxLength(32), v.trim()), - totalMoneyEarned: v.optional( - v.pipe( - v.number(), - v.minValue(0), - v.maxValue(1000000000), - v.transform((v) => Number(v)), - ), - ), - fishCaught: v.optional( - v.pipe( - v.union([v.string(), v.number()]), - v.minValue(0), - v.maxValue(100000), - v.transform((v) => Number(v)), - ), - ), - numObelisks: v.optional( - v.pipe( - v.union([v.string(), v.number()]), - v.minValue(0), - v.maxValue(4), - v.transform((v) => Number(v)), - ), - ), - goldenClock: v.optional(v.boolean()), - childrenCount: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(2), - ), - ), - houseUpgradeLevel: v.optional( - v.pipe( - v.union([v.string(), v.number()]), - v.minValue(0), - v.maxValue(3), - v.transform((v) => Number(v)), - ), - ), - farming: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(10), - ), - ), - fishing: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(10), - ), - ), - foraging: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(10), - ), - ), - mining: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(10), - ), - ), - combat: v.optional( - v.pipe( - v.union([v.string(), v.number()]), // Accepts both string and number inputs - v.transform(Number), // Converts to a number - v.number(), - v.minValue(0), - v.maxValue(10), - ), - ), -}); +import { formSchema } from "./create"; export default function Editor() { const { activePlayer, uploadPlayers } = usePlayers(); @@ -184,8 +73,8 @@ export default function Editor() { return [farmName, farmType]; }, [activePlayer]); - const form = useForm>({ - resolver: valibotResolver(formSchema as any), + const form = useForm>({ + resolver: zodResolver(formSchema as any), defaultValues: { name: "", gameVersion: undefined, @@ -251,7 +140,7 @@ export default function Editor() { _setGameVersion(activePlayer?.general?.gameVersion ?? undefined); }, [activePlayer, form, farmListInfo]); - const onSubmit = async (values: v.InferOutput) => { + const onSubmit = async (values: z.infer) => { if (!activePlayer?._id) { toast.error("An error occurred creating your farmhand.", { description: ( @@ -284,23 +173,23 @@ export default function Editor() { experience: { farming: values.farming === activePlayer.general?.skills?.farming - ? activePlayer.general?.experience?.farming ?? 0 + ? (activePlayer.general?.experience?.farming ?? 0) : 0, fishing: values.fishing === activePlayer.general?.skills?.fishing - ? activePlayer.general?.experience?.fishing ?? 0 + ? (activePlayer.general?.experience?.fishing ?? 0) : 0, foraging: values.foraging === activePlayer.general?.skills?.foraging - ? activePlayer.general?.experience?.foraging ?? 0 + ? (activePlayer.general?.experience?.foraging ?? 0) : 0, mining: values.mining === activePlayer.general?.skills?.mining - ? activePlayer.general?.experience?.mining ?? 0 + ? (activePlayer.general?.experience?.mining ?? 0) : 0, combat: values.combat === activePlayer.general?.skills?.combat - ? activePlayer.general?.experience?.combat ?? 0 + ? (activePlayer.general?.experience?.combat ?? 0) : 0, luck: 0, },