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 { ArrowRight, Check, LockKeyhole, X } from "lucide-react";
import { useMemo, useState } from "react";
@@ -9,7 +18,6 @@ import { z } from "zod";
import useAuth from "@/hooks/useAuth";
import AuthLayout from "@/components/auth/AuthLayout";
import {
PASSWORD_MISMATCH,
confirmPasswordField,
passwordField,
passwordRequirements,
@@ -21,7 +29,10 @@ const passwordSchema = z
password: passwordField,
confirmPassword: confirmPasswordField,
})
.refine(samePassword, PASSWORD_MISMATCH);
.refine(samePassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
});
type FormData = z.infer<typeof passwordSchema>;
@@ -44,7 +55,8 @@ export default function SetPasswordPage() {
const password = watch("password");
const requirements = useMemo(
() => passwordRequirements.map((r) => ({ ...r, met: r.test(password || "") })),
() =>
passwordRequirements.map((r) => ({ ...r, met: r.test(password || "") })),
[password],
);
@@ -83,11 +95,21 @@ export default function SetPasswordPage() {
"Secure freight operations",
"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">
<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)" />
</Box>
<Box>

View File

@@ -27,7 +27,6 @@ import PasswordChecklist from "@/components/auth/PasswordChecklist";
import { ControlledPhoneField, isValidPhone } from "@/components/PhoneField";
import { api } from "@/services/api";
import {
PASSWORD_MISMATCH,
confirmPasswordField,
passwordField,
samePassword,
@@ -53,7 +52,10 @@ const userSchema = z
password: passwordField,
confirmPassword: confirmPasswordField,
})
.refine(samePassword, PASSWORD_MISMATCH);
.refine(samePassword, {
message: "Passwords do not match",
path: ["confirmPassword"],
});
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 lowercase letter", test: (v: string) => /[a-z]/.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;
/**
@@ -21,15 +24,14 @@ export const passwordField = z
.regex(/\d/, "Password must include a number")
.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 }) =>
data.password === data.confirmPassword;
export const PASSWORD_MISMATCH = {
message: "Passwords do not match",
path: ["confirmPassword"],
} as const;
export const samePassword = (data: {
password: string;
confirmPassword: string;
}) => data.password === data.confirmPassword;
/** Every requirement in {@link passwordRequirements} is satisfied. */
export const meetsAllRequirements = (value: string) =>