Password validation with zod
This commit is contained in:
@@ -4,21 +4,35 @@ import { useRouter } from "next/router";
|
|||||||
import { Button } from "@documenso/ui";
|
import { Button } from "@documenso/ui";
|
||||||
import Logo from "./logo";
|
import Logo from "./logo";
|
||||||
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import * as z from "zod";
|
||||||
|
|
||||||
interface ResetPasswordForm {
|
const schema = z
|
||||||
password: string;
|
.object({
|
||||||
confirmPassword: string;
|
password: z.string().min(8, { message: "Password must be at least 8 characters" }),
|
||||||
}
|
confirmPassword: z.string().min(8, { message: "Password must be at least 8 characters" }),
|
||||||
|
})
|
||||||
|
.refine((data) => data.password === data.confirmPassword, {
|
||||||
|
path: ["confirmPassword"],
|
||||||
|
message: "Password don't match",
|
||||||
|
});
|
||||||
|
|
||||||
|
type ResetPasswordForm = z.infer<typeof schema>;
|
||||||
|
|
||||||
export default function ResetPassword() {
|
export default function ResetPassword() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { token } = router.query;
|
const { token } = router.query;
|
||||||
|
|
||||||
const methods = useForm<ResetPasswordForm>();
|
const methods = useForm<ResetPasswordForm>({
|
||||||
const { register, formState, watch } = methods;
|
resolver: zodResolver(schema),
|
||||||
const password = watch("password", "");
|
});
|
||||||
|
const {
|
||||||
|
register,
|
||||||
|
formState: { errors, isSubmitting },
|
||||||
|
handleSubmit,
|
||||||
|
} = methods;
|
||||||
|
|
||||||
const [resetSuccessful, setResetSuccessful] = useState(false);
|
const [resetSuccessful, setResetSuccessful] = useState(false);
|
||||||
|
|
||||||
@@ -67,7 +81,7 @@ export default function ResetPassword() {
|
|||||||
</div>
|
</div>
|
||||||
{resetSuccessful ? null : (
|
{resetSuccessful ? null : (
|
||||||
<FormProvider {...methods}>
|
<FormProvider {...methods}>
|
||||||
<form className="mt-8 space-y-6" onSubmit={methods.handleSubmit(onSubmit)}>
|
<form className="mt-8 space-y-6" onSubmit={handleSubmit(onSubmit)}>
|
||||||
<div className="-space-y-px rounded-md shadow-sm">
|
<div className="-space-y-px rounded-md shadow-sm">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="password" className="sr-only">
|
<label htmlFor="password" className="sr-only">
|
||||||
@@ -89,10 +103,7 @@ export default function ResetPassword() {
|
|||||||
Password
|
Password
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
{...register("confirmPassword", {
|
{...register("confirmPassword")}
|
||||||
required: "Please confirm password",
|
|
||||||
validate: (value) => value === password || "The passwords do not match",
|
|
||||||
})}
|
|
||||||
id="confirmPassword"
|
id="confirmPassword"
|
||||||
name="confirmPassword"
|
name="confirmPassword"
|
||||||
type="password"
|
type="password"
|
||||||
@@ -103,10 +114,14 @@ export default function ResetPassword() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{errors && (
|
||||||
|
<span className="text-xs text-red-500">{errors.confirmPassword?.message}</span>
|
||||||
|
)}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={formState.isSubmitting}
|
disabled={isSubmitting}
|
||||||
className="group relative flex w-full">
|
className="group relative flex w-full">
|
||||||
Reset password
|
Reset password
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
31
package-lock.json
generated
31
package-lock.json
generated
@@ -15,6 +15,7 @@
|
|||||||
"@documenso/prisma": "*",
|
"@documenso/prisma": "*",
|
||||||
"@headlessui/react": "^1.7.4",
|
"@headlessui/react": "^1.7.4",
|
||||||
"@heroicons/react": "^2.0.13",
|
"@heroicons/react": "^2.0.13",
|
||||||
|
"@hookform/resolvers": "^3.1.0",
|
||||||
"avatar-from-initials": "^1.0.3",
|
"avatar-from-initials": "^1.0.3",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"next": "13.2.4",
|
"next": "13.2.4",
|
||||||
@@ -24,7 +25,8 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hook-form": "^7.41.5",
|
"react-hook-form": "^7.41.5",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
"react-signature-canvas": "^1.0.6"
|
"react-signature-canvas": "^1.0.6",
|
||||||
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
@@ -525,6 +527,14 @@
|
|||||||
"react": ">= 16"
|
"react": ">= 16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@hookform/resolvers": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0A8K+Nxq+f83Whm/ajlwE6VtQlp/yPHZnXw7XWVPIGm1Vx0QV8KThU3BpbBRfAZ7/dYqCKKBNnQh85BkmBKkA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react-hook-form": "^7.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanwhocodes/config-array": {
|
"node_modules/@humanwhocodes/config-array": {
|
||||||
"version": "0.11.8",
|
"version": "0.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||||
@@ -8048,6 +8058,14 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/zod": {
|
||||||
|
"version": "3.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||||
|
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/features": {
|
"packages/features": {
|
||||||
"name": "@documenso/features",
|
"name": "@documenso/features",
|
||||||
"version": "0.0.0"
|
"version": "0.0.0"
|
||||||
@@ -8507,6 +8525,12 @@
|
|||||||
"integrity": "sha512-x89rFxH3SRdYaA+JCXwfe+RkE1SFTo9GcOkZettHer71Y3T7V+ogKmfw5CjTazgS3d0ClJ7p1NA+SP7VQLQcLw==",
|
"integrity": "sha512-x89rFxH3SRdYaA+JCXwfe+RkE1SFTo9GcOkZettHer71Y3T7V+ogKmfw5CjTazgS3d0ClJ7p1NA+SP7VQLQcLw==",
|
||||||
"requires": {}
|
"requires": {}
|
||||||
},
|
},
|
||||||
|
"@hookform/resolvers": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-z0A8K+Nxq+f83Whm/ajlwE6VtQlp/yPHZnXw7XWVPIGm1Vx0QV8KThU3BpbBRfAZ7/dYqCKKBNnQh85BkmBKkA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"@humanwhocodes/config-array": {
|
"@humanwhocodes/config-array": {
|
||||||
"version": "0.11.8",
|
"version": "0.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
|
||||||
@@ -14097,6 +14121,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
},
|
||||||
|
"zod": {
|
||||||
|
"version": "3.21.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
|
||||||
|
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"@documenso/prisma": "*",
|
"@documenso/prisma": "*",
|
||||||
"@headlessui/react": "^1.7.4",
|
"@headlessui/react": "^1.7.4",
|
||||||
"@heroicons/react": "^2.0.13",
|
"@heroicons/react": "^2.0.13",
|
||||||
|
"@hookform/resolvers": "^3.1.0",
|
||||||
"avatar-from-initials": "^1.0.3",
|
"avatar-from-initials": "^1.0.3",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"next": "13.2.4",
|
"next": "13.2.4",
|
||||||
@@ -35,7 +36,8 @@
|
|||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hook-form": "^7.41.5",
|
"react-hook-form": "^7.41.5",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
"react-signature-canvas": "^1.0.6"
|
"react-signature-canvas": "^1.0.6",
|
||||||
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/forms": "^0.5.3",
|
"@tailwindcss/forms": "^0.5.3",
|
||||||
@@ -54,4 +56,4 @@
|
|||||||
"turbo": "^1.9.9",
|
"turbo": "^1.9.9",
|
||||||
"typescript": "4.8.4"
|
"typescript": "4.8.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user