'use client'; import { useState } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { toast } from 'sonner'; import { CheckCircle2, Circle } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; const passwordSchema = z .object({ password: z .string() .min(12, 'Must be at least 12 characters') .regex(/[A-Z]/, 'Must contain an uppercase letter') .regex(/[a-z]/, 'Must contain a lowercase letter') .regex(/[0-9]/, 'Must contain a number') .regex(/[^A-Za-z0-9]/, 'Must contain a special character'), confirmPassword: z.string().min(1, 'Please confirm your password'), }) .refine((data) => data.password === data.confirmPassword, { message: 'Passwords do not match', path: ['confirmPassword'], }); type SetPasswordFormData = z.infer; type Requirement = { label: string; test: (value: string) => boolean; }; const requirements: Requirement[] = [ { label: 'At least 12 characters', test: (v) => v.length >= 12 }, { label: 'Uppercase letter', test: (v) => /[A-Z]/.test(v) }, { label: 'Lowercase letter', test: (v) => /[a-z]/.test(v) }, { label: 'Number', test: (v) => /[0-9]/.test(v) }, { label: 'Special character', test: (v) => /[^A-Za-z0-9]/.test(v) }, ]; export default function SetPasswordPage() { const router = useRouter(); const searchParams = useSearchParams(); const token = searchParams.get('token'); const [isLoading, setIsLoading] = useState(false); const [passwordValue, setPasswordValue] = useState(''); const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(passwordSchema), }); async function onSubmit(data: SetPasswordFormData) { if (!token) { toast.error('Invalid or missing reset token. Please request a new password reset link.'); return; } setIsLoading(true); try { const response = await fetch('/api/auth/set-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, password: data.password }), }); if (!response.ok) { const body = await response.json().catch(() => ({})); toast.error(body.message ?? 'Failed to set password. Please try again.'); return; } toast.success('Password set successfully. You can now sign in.'); router.push('/login'); } catch { toast.error('Something went wrong. Please try again.'); } finally { setIsLoading(false); } } return (

Port Nimara

Set your password

{!token ? (

Invalid or missing token. Please request a new password reset link.

) : (
setPasswordValue(e.target.value), })} /> {errors.password && (

{errors.password.message}

)}
    {requirements.map((req) => { const met = req.test(passwordValue); return (
  • {met ? ( ) : ( )} {req.label}
  • ); })}
{errors.confirmPassword && (

{errors.confirmPassword.message}

)}
)}
); }