diff --git a/package.json b/package.json index 0983ab6..08a9141 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "no-copy-frontend", - "version": "0.6.0", + "version": "0.7.0", "private": true, "scripts": { "dev": "next dev -p 2999", diff --git a/src/app/actions/auth.ts b/src/app/actions/auth.ts index b8b1222..d65a6b9 100644 --- a/src/app/actions/auth.ts +++ b/src/app/actions/auth.ts @@ -133,7 +133,7 @@ export async function authorization( redirect('/pages/dashboard'); } -type FormState = { +export type FormState = { previousState: { fullName: string; email: string; @@ -225,8 +225,6 @@ export async function registration( await createSession(parsed.message_body.token, email); } else { console.log('error'); - /* console.log(parsed.message_body); */ - /* throw (`${parsed.message_code.fieldErrors}`); */ throw parsed; } } else { diff --git a/src/app/ui/forms/register-form.tsx b/src/app/ui/forms/register-form.tsx index ec93b16..71fa2c2 100644 --- a/src/app/ui/forms/register-form.tsx +++ b/src/app/ui/forms/register-form.tsx @@ -1,22 +1,30 @@ 'use client' import styles from '@/app/styles/login.module.scss'; -import { useActionState, useState } from 'react'; -import { registration } from '@/app/actions/auth'; +import { ChangeEvent, useActionState, useEffect, useRef, useState } from 'react'; +import { registration, FormState } from '@/app/actions/auth'; import PhoneInput from '@/app/ui/inputs/phone-input'; import Link from 'next/link'; import { useTranslations } from 'next-intl'; import { IconEye } from '@/app/ui/icons/icons'; +import { SignupFormSchema } from '@/app/actions/definitions'; +import * as z from 'zod' export default function RegisterForm() { const [state, formAction, isPending] = useActionState( registration, undefined, ); - const t = useTranslations('Login-register-form'); + const t = useTranslations('Login-register-form'); const [showPassword, setShowPassword] = useState(false); const [showConfirmPassword, setShowConfirmPassword] = useState(false); + const [formState, setFormState] = useState(undefined); + const passwordRef = useRef(null); + + useEffect(() => { + setFormState(state); + }, [state]) function handleMouseDown(target: 'password' | 'confirm-password') { if (target === 'password') { @@ -43,6 +51,71 @@ export default function RegisterForm() { } } + function validateField( + fieldName: string, + value: string, + ) { + switch (fieldName) { + case 'confirm_password': + const baseSchema = SignupFormSchema.shape.confirm_password; + const baseResult = baseSchema.safeParse(value); + + if (!baseResult.success) { + return baseResult; + } + + const currentPassword = passwordRef.current?.value || ''; + if (value !== currentPassword) { + return { + success: false, + error: new z.ZodError([ + { + code: z.ZodIssueCode.custom, + message: 'repeat-password', + path: ['confirm_password'] + } + ]) + }; + } + + return { success: true, data: value }; + + case 'email': + case 'fullName': + case 'phone': + case 'password': + case 'agree': + const schema = SignupFormSchema.shape[fieldName]; + if (fieldName === 'phone') { + return schema.safeParse(value.replace(/[-\(\)\s]/g, '')); + } + return schema.safeParse(value); + + default: + throw new Error(`Unknown field: ${fieldName}`); + } + } + + function onChangeHandler(e: ChangeEvent): void { + const fieldName = e.target.name; + const validatedField = validateField(fieldName, e.target.value); + + if (validatedField.success) { + setFormState(prevState => { + if (!prevState?.error || !prevState?.error[fieldName]) { + return prevState; + } + + const { [fieldName]: _, ...newError } = prevState.error; + + return { + ...prevState, + error: newError + }; + }); + } + } + return (
{ formAction(e); @@ -59,12 +132,13 @@ export default function RegisterForm() { name="fullName" className={`${styles['form-input']}`} placeholder={t('name-placeholder')} - defaultValue={state?.previousState?.fullName ? state?.previousState?.fullName : ''} + defaultValue={formState?.previousState?.fullName ? formState?.previousState?.fullName : ''} + onChange={onChangeHandler} /> - {state?.error?.fullName && ( + {formState?.error?.fullName && (

{ - state?.error?.fullName.split('&').map((e) => { + formState?.error?.fullName.split('&').map((e) => { return t(e) + " " }) } @@ -82,12 +156,13 @@ export default function RegisterForm() { name="email" className={`${styles['form-input']}`} placeholder="ivan@example.com" - defaultValue={state?.previousState?.email ? state?.previousState?.email : ''} + defaultValue={formState?.previousState?.email ? formState?.previousState?.email : ''} + onChange={onChangeHandler} /> - {state?.error?.email && ( + {formState?.error?.email && (

{ - state?.error?.email.split('&').map((e) => { + formState?.error?.email.split('&').map((e) => { return t(e) + " " }) } @@ -98,10 +173,10 @@ export default function RegisterForm() { - - {state?.error?.phone && ( + + {formState?.error?.phone && (

- {t(state?.error?.phone)} + {t(formState?.error?.phone)}

)} @@ -118,7 +193,7 @@ export default function RegisterForm() { name="companyName" className={`${styles['form-input']}`} placeholder={t('company-placeholder')} - defaultValue={state?.previousState?.companyName ? state?.previousState?.companyName : ''} + defaultValue={formState?.previousState?.companyName ? formState?.previousState?.companyName : ''} />
@@ -130,11 +205,13 @@ export default function RegisterForm() { className={`${styles['password-wrapper']}`} >
- {state?.error?.password && ( + {formState?.error?.password && (

{ - state?.error?.password.split('&').map((e) => { + formState?.error?.password.split('&').map((e) => { return t(e) }) } @@ -173,7 +250,8 @@ export default function RegisterForm() { name="confirm_password" className={`${styles['form-input']}`} placeholder={t('repeat-password')} - defaultValue={state?.previousState?.confirm_password ? state?.previousState?.confirm_password : ''} + defaultValue={formState?.previousState?.confirm_password ? formState?.previousState?.confirm_password : ''} + onChange={onChangeHandler} /> - {state?.error?.confirm_password && ( + {formState?.error?.confirm_password && (

- {t(state?.error?.confirm_password)} + {t(formState?.error?.confirm_password)}

)} @@ -203,7 +281,8 @@ export default function RegisterForm() { type="checkbox" id="agree" name="agree" - defaultChecked={state?.previousState?.agree ? true : false} + defaultChecked={formState?.previousState?.agree ? true : false} + onChange={onChangeHandler} /> - {state?.error?.agree && ( + {formState?.error?.agree && (

- {t(state?.error?.agree)} + {t(formState?.error?.agree)}

)} - {state?.error?.server && ( + {formState?.error?.server && (

- {t(state?.error?.server)} + {t(formState?.error?.server)}

)}