This commit is contained in:
Nathnael
2026-07-09 08:55:06 +00:00
parent e3baf27a3e
commit 3f7734fe16
3 changed files with 43 additions and 17 deletions

View File

@@ -1,4 +1,13 @@
import { Alert, Box, Button, Group, PasswordInput, Stack, Text, ThemeIcon } from "@mantine/core"; import {
Alert,
Box,
Button,
Group,
PasswordInput,
Stack,
Text,
ThemeIcon,
} from "@mantine/core";
import { zodResolver } from "@hookform/resolvers/zod"; import { zodResolver } from "@hookform/resolvers/zod";
import { ArrowRight, Check, LockKeyhole, X } from "lucide-react"; import { ArrowRight, Check, LockKeyhole, X } from "lucide-react";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
@@ -9,7 +18,6 @@ import { z } from "zod";
import useAuth from "@/hooks/useAuth"; import useAuth from "@/hooks/useAuth";
import AuthLayout from "@/components/auth/AuthLayout"; import AuthLayout from "@/components/auth/AuthLayout";
import { import {
PASSWORD_MISMATCH,
confirmPasswordField, confirmPasswordField,
passwordField, passwordField,
passwordRequirements, passwordRequirements,
@@ -21,7 +29,10 @@ const passwordSchema = z
password: passwordField, password: passwordField,
confirmPassword: confirmPasswordField, confirmPassword: confirmPasswordField,
}) })
.refine(samePassword, PASSWORD_MISMATCH); .refine(samePassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
});
type FormData = z.infer<typeof passwordSchema>; type FormData = z.infer<typeof passwordSchema>;
@@ -44,7 +55,8 @@ export default function SetPasswordPage() {
const password = watch("password"); const password = watch("password");
const requirements = useMemo( const requirements = useMemo(
() => passwordRequirements.map((r) => ({ ...r, met: r.test(password || "") })), () =>
passwordRequirements.map((r) => ({ ...r, met: r.test(password || "") })),
[password], [password],
); );
@@ -83,11 +95,21 @@ export default function SetPasswordPage() {
"Secure freight operations", "Secure freight operations",
"Advanced authentication system", "Advanced authentication system",
], ],
stats: { label: "Security Protection", value: "256-bit", footer: "Encrypted", progress: "w-[98%]" }, stats: {
label: "Security Protection",
value: "256-bit",
footer: "Encrypted",
progress: "w-[98%]",
},
}} }}
> >
<Stack gap="xs" mb="lg"> <Stack gap="xs" mb="lg">
<Box w={48} h={48} bg="edr-soft" className="flex items-center justify-center rounded-2xl"> <Box
w={48}
h={48}
bg="edr-soft"
className="flex items-center justify-center rounded-2xl"
>
<LockKeyhole size={22} color="var(--mantine-color-edr-green-6)" /> <LockKeyhole size={22} color="var(--mantine-color-edr-green-6)" />
</Box> </Box>
<Box> <Box>

View File

@@ -27,7 +27,6 @@ import PasswordChecklist from "@/components/auth/PasswordChecklist";
import { ControlledPhoneField, isValidPhone } from "@/components/PhoneField"; import { ControlledPhoneField, isValidPhone } from "@/components/PhoneField";
import { api } from "@/services/api"; import { api } from "@/services/api";
import { import {
PASSWORD_MISMATCH,
confirmPasswordField, confirmPasswordField,
passwordField, passwordField,
samePassword, samePassword,
@@ -53,7 +52,10 @@ const userSchema = z
password: passwordField, password: passwordField,
confirmPassword: confirmPasswordField, confirmPassword: confirmPasswordField,
}) })
.refine(samePassword, PASSWORD_MISMATCH); .refine(samePassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
});
type FormData = z.infer<typeof userSchema>; type FormData = z.infer<typeof userSchema>;

View File

@@ -6,7 +6,10 @@ export const passwordRequirements = [
{ label: "One uppercase letter", test: (v: string) => /[A-Z]/.test(v) }, { label: "One uppercase letter", test: (v: string) => /[A-Z]/.test(v) },
{ label: "One lowercase letter", test: (v: string) => /[a-z]/.test(v) }, { label: "One lowercase letter", test: (v: string) => /[a-z]/.test(v) },
{ label: "One number", test: (v: string) => /\d/.test(v) }, { label: "One number", test: (v: string) => /\d/.test(v) },
{ label: "One special character", test: (v: string) => /[^A-Za-z0-9]/.test(v) }, {
label: "One special character",
test: (v: string) => /[^A-Za-z0-9]/.test(v),
},
] as const; ] as const;
/** /**
@@ -21,15 +24,14 @@ export const passwordField = z
.regex(/\d/, "Password must include a number") .regex(/\d/, "Password must include a number")
.regex(/[^A-Za-z0-9]/, "Password must include a special character"); .regex(/[^A-Za-z0-9]/, "Password must include a special character");
export const confirmPasswordField = z.string().min(1, "Please confirm your password"); export const confirmPasswordField = z
.string()
.min(1, "Please confirm your password");
export const samePassword = (data: { password: string; confirmPassword: string }) => export const samePassword = (data: {
data.password === data.confirmPassword; password: string;
confirmPassword: string;
export const PASSWORD_MISMATCH = { }) => data.password === data.confirmPassword;
message: "Passwords do not match",
path: ["confirmPassword"],
} as const;
/** Every requirement in {@link passwordRequirements} is satisfied. */ /** Every requirement in {@link passwordRequirements} is satisfied. */
export const meetsAllRequirements = (value: string) => export const meetsAllRequirements = (value: string) =>