edit validation messages, saving formData
This commit is contained in:
+91
-17
@@ -1,6 +1,6 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import {SignupFormSchema, loginFormSchema, localDevelopmentUrl} from '@/app/lib/definitions';
|
import { SignupFormSchema, loginFormSchema, localDevelopmentUrl } from '@/app/lib/definitions';
|
||||||
import { createSession, deleteSession, getSessionData } from '@/app/lib/session';
|
import { createSession, deleteSession, getSessionData } from '@/app/lib/session';
|
||||||
import { redirect } from 'next/navigation';
|
import { redirect } from 'next/navigation';
|
||||||
|
|
||||||
@@ -29,16 +29,41 @@ export async function logout() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function authorization(
|
export async function authorization(
|
||||||
state: string | undefined,
|
state: {
|
||||||
|
previousState: {
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
error: Record<string, string>
|
||||||
|
} | undefined,
|
||||||
formData: FormData,
|
formData: FormData,
|
||||||
) {
|
) {
|
||||||
|
const email = formData.get('email') as string || '';
|
||||||
|
const password = formData.get('password');
|
||||||
|
|
||||||
const validatedFields = loginFormSchema.safeParse({
|
const validatedFields = loginFormSchema.safeParse({
|
||||||
email: formData.get('email'),
|
email,
|
||||||
password: formData.get('password'),
|
password
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!validatedFields.success) {
|
if (!validatedFields.success) {
|
||||||
return 'error';
|
const errors: Record<string, string> = {}
|
||||||
|
JSON.parse(validatedFields.error.message).forEach((obj: {
|
||||||
|
message: string,
|
||||||
|
path: string
|
||||||
|
}) => {
|
||||||
|
if (errors[obj.path[0]]) {
|
||||||
|
errors[obj.path[0]] = `${errors[obj.path[0]]} ${obj.message}`;
|
||||||
|
} else {
|
||||||
|
errors[obj.path[0]] = obj.message;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
previousState: {
|
||||||
|
email
|
||||||
|
},
|
||||||
|
error: errors
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -58,12 +83,21 @@ export async function authorization(
|
|||||||
let parsed = await response.json();
|
let parsed = await response.json();
|
||||||
await createSession(parsed.token, parsed.email);
|
await createSession(parsed.token, parsed.email);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Something went wrong. from server');
|
throw new Error(`Something went wrong. Status from server ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const errors: Record<string, string> = {}
|
||||||
|
errors['server'] = `${error}`;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return 'Something went wrong. from server';
|
return {
|
||||||
|
previousState: {
|
||||||
|
email,
|
||||||
|
password
|
||||||
|
},
|
||||||
|
error: errors
|
||||||
|
};
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -71,16 +105,35 @@ export async function authorization(
|
|||||||
redirect('/pages/dashboard');
|
redirect('/pages/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FormState = {
|
||||||
|
previousState: {
|
||||||
|
full_name: string;
|
||||||
|
email: string;
|
||||||
|
password: string;
|
||||||
|
confirm_password: string;
|
||||||
|
phone: string;
|
||||||
|
company: string;
|
||||||
|
}
|
||||||
|
error: Record<string, string>
|
||||||
|
};
|
||||||
|
|
||||||
export async function registration(
|
export async function registration(
|
||||||
state: Record<string, string> | undefined,
|
state: FormState | undefined,
|
||||||
formData: FormData,
|
formData: FormData,
|
||||||
) {
|
): Promise<FormState> {
|
||||||
|
const full_name = formData.get('full_name') as string || '';
|
||||||
|
const email = formData.get('email') as string || '';
|
||||||
|
const password = formData.get('password') as string || '';
|
||||||
|
const confirm_password = formData.get('confirm_password') as string || '';
|
||||||
|
const phone = formData.get('phone') as string || '';
|
||||||
|
const company = formData.get('company') as string || '';
|
||||||
|
|
||||||
const validatedFields = SignupFormSchema.safeParse({
|
const validatedFields = SignupFormSchema.safeParse({
|
||||||
full_name: formData.get('full_name'),
|
full_name,
|
||||||
email: formData.get('email'),
|
email,
|
||||||
password: formData.get('password'),
|
password,
|
||||||
confirm_password: formData.get('confirm_password'),
|
confirm_password,
|
||||||
})
|
});
|
||||||
|
|
||||||
if (!validatedFields.success) {
|
if (!validatedFields.success) {
|
||||||
const errors: Record<string, string> = {}
|
const errors: Record<string, string> = {}
|
||||||
@@ -95,14 +148,24 @@ export async function registration(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return errors;
|
return {
|
||||||
|
previousState: {
|
||||||
|
full_name,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
confirm_password,
|
||||||
|
phone,
|
||||||
|
company
|
||||||
|
},
|
||||||
|
error: errors
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { full_name, email, password } = validatedFields.data;
|
const { full_name, email, password } = validatedFields.data;
|
||||||
const response = await fetch(`${API_BASE_URL}/v1/api/auth/register`, {
|
const response = await fetch(`${API_BASE_URL}/v1/api/auth/register`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ fullName: full_name, email, password }),
|
body: JSON.stringify({ fullName: full_name, email, password, phone, company }),
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
@@ -121,7 +184,18 @@ export async function registration(
|
|||||||
if (error) {
|
if (error) {
|
||||||
const errors: Record<string, string> = {}
|
const errors: Record<string, string> = {}
|
||||||
errors['server'] = `-error-2 -> ${error}`
|
errors['server'] = `-error-2 -> ${error}`
|
||||||
return errors;
|
|
||||||
|
return {
|
||||||
|
previousState: {
|
||||||
|
full_name,
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
confirm_password,
|
||||||
|
phone,
|
||||||
|
company
|
||||||
|
},
|
||||||
|
error: errors
|
||||||
|
};
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,20 +20,20 @@ export const SignupFormSchema = z
|
|||||||
.object({
|
.object({
|
||||||
full_name: z
|
full_name: z
|
||||||
.string()
|
.string()
|
||||||
.min(3, { error: 'Name must be at least 3 characters long.' })
|
.min(3, { error: 'Имя должно содержать не менее 3 символов.' })
|
||||||
.trim(),
|
.trim(),
|
||||||
email: z.email({ error: 'Please enter a valid email.' }).trim(),
|
email: z.email({ error: 'Пожалуйста, введите правильный адрес электронной почты.' }).trim(),
|
||||||
password: z
|
password: z
|
||||||
.string()
|
.string()
|
||||||
.min(8, { error: 'Be at least 8 characters long' })
|
.min(8, { error: 'Длина пароля должна быть не менее 8 символов.' })
|
||||||
.regex(/[a-zA-Z]/, { error: 'Contain at least one letter.' })
|
.regex(/[a-zA-Z]/, { error: 'Пароль должен содержать хотя бы одну букву.' })
|
||||||
.regex(/[0-9]/, { error: 'Contain at least one number.' })
|
.regex(/[0-9]/, { error: 'Пароль должен содержать хотя бы одну цифру.' })
|
||||||
.trim(),
|
.trim(),
|
||||||
confirm_password: z
|
confirm_password: z
|
||||||
.string()
|
.string()
|
||||||
})
|
})
|
||||||
.refine((data) => data.password === data.confirm_password, {
|
.refine((data) => data.password === data.confirm_password, {
|
||||||
message: 'passwordMismatchErrorMessage',
|
message: 'Повторите пароль',
|
||||||
path: ['confirm_password'],
|
path: ['confirm_password'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -41,11 +41,11 @@ export const loginFormSchema = z
|
|||||||
.object({
|
.object({
|
||||||
email: z
|
email: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, { error: 'Email must be not empty' })
|
.min(1, { error: 'Адрес электронной почты не должен быть пустым' })
|
||||||
.trim(),
|
.trim(),
|
||||||
password: z
|
password: z
|
||||||
.string()
|
.string()
|
||||||
.min(1, { error: 'Password must be not empty' })
|
.min(1, { error: 'Пароль не должен быть пустым' })
|
||||||
.trim(),
|
.trim(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useActionState } from 'react';
|
|||||||
import { authorization } from '@/app/actions/auth';
|
import { authorization } from '@/app/actions/auth';
|
||||||
|
|
||||||
export default function LoginForm() {
|
export default function LoginForm() {
|
||||||
const [errorMessage, formAction, isPending] = useActionState(
|
const [state, formAction, isPending] = useActionState(
|
||||||
authorization,
|
authorization,
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
@@ -14,14 +14,33 @@ export default function LoginForm() {
|
|||||||
<form action={formAction}>
|
<form action={formAction}>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']}`}>Email адрес</label>
|
<label className={`${styles['form-label']}`}>Email адрес</label>
|
||||||
<input type="readOnly" id="email" name="email" className={`${styles['form-input']}`} placeholder="Введите ваш email" />
|
<input
|
||||||
|
type="readOnly"
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="Введите ваш email"
|
||||||
|
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||||
|
/>
|
||||||
|
{state?.error?.email && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.email}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']}`}>Пароль</label>
|
<label className={`${styles['form-label']}`}>Пароль</label>
|
||||||
<input type="password" id="password" name="password" className={`${styles['form-input']}`} placeholder="Введите пароль" />
|
<input
|
||||||
|
type="password"
|
||||||
|
id="password"
|
||||||
|
name="password"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="Введите пароль"
|
||||||
|
/>
|
||||||
|
{state?.error?.password && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.password}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{errorMessage && (
|
{state?.error.server && (
|
||||||
<p className="text-sm text-red-500">{errorMessage}</p>
|
<p className="text-sm text-red-500">{state?.error.server}</p>
|
||||||
)}
|
)}
|
||||||
<div className={`${styles['form-options']}`}>
|
<div className={`${styles['form-options']}`}>
|
||||||
<div className={`${styles['form-checkbox']}`}>
|
<div className={`${styles['form-checkbox']}`}>
|
||||||
|
|||||||
@@ -1,19 +1,15 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import styles from '@/app/styles/login.module.scss';
|
import styles from '@/app/styles/login.module.scss';
|
||||||
import { useActionState, useEffect } from 'react';
|
import { useActionState } from 'react';
|
||||||
import { registration } from '@/app/actions/auth';
|
import { registration } from '@/app/actions/auth';
|
||||||
|
|
||||||
export default function RegisterForm() {
|
export default function RegisterForm() {
|
||||||
const [errorMessage, formAction, isPending] = useActionState(
|
const [state, formAction, isPending] = useActionState(
|
||||||
registration,
|
registration,
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log(errorMessage);
|
|
||||||
}, [errorMessage])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form action={(e) => {
|
<form action={(e) => {
|
||||||
formAction(e);
|
formAction(e);
|
||||||
@@ -24,22 +20,43 @@ export default function RegisterForm() {
|
|||||||
>
|
>
|
||||||
Полное имя
|
Полное имя
|
||||||
</label>
|
</label>
|
||||||
<input type="text" id="full_name" name="full_name" className={`${styles['form-input']}`} placeholder="Иванов Иван Иванович" />
|
<input
|
||||||
{errorMessage?.full_name && (
|
type="text"
|
||||||
<p className="text-sm text-red-500">{errorMessage!.full_name}</p>
|
id="full_name"
|
||||||
|
name="full_name"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="Иванов Иван Иванович"
|
||||||
|
defaultValue={state?.previousState?.full_name ? state?.previousState?.full_name : ''}
|
||||||
|
/>
|
||||||
|
{state?.error?.full_name && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.full_name}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-row']}`}>
|
<div className={`${styles['form-row']}`}>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']} ${styles['required']}`}>Email адрес</label>
|
<label className={`${styles['form-label']} ${styles['required']}`}>Email адрес</label>
|
||||||
<input type="text" id="email" name="email" className={`${styles['form-input']}`} placeholder="ivan@example.com" />
|
<input
|
||||||
{errorMessage?.email && (
|
type="text"
|
||||||
<p className="text-sm text-red-500">{errorMessage!.email}</p>
|
id="email"
|
||||||
|
name="email"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="ivan@example.com"
|
||||||
|
defaultValue={state?.previousState?.email ? state?.previousState?.email : ''}
|
||||||
|
/>
|
||||||
|
{state?.error?.email && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.email}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']}`}>Телефон</label>
|
<label className={`${styles['form-label']}`}>Телефон</label>
|
||||||
<input type="phone" id="phone" name="phone" className={`${styles['form-input']}`} placeholder="+7 (999) 123-45-67" />
|
<input
|
||||||
|
type="phone"
|
||||||
|
id="phone"
|
||||||
|
name="phone"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="+7 (999) 123-45-67"
|
||||||
|
defaultValue={state?.previousState?.phone ? state?.previousState?.phone : ''}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
@@ -48,21 +65,41 @@ export default function RegisterForm() {
|
|||||||
>
|
>
|
||||||
Компания
|
Компания
|
||||||
</label>
|
</label>
|
||||||
<input type="text" id="company" name="company" className={`${styles['form-input']}`} placeholder="ООО «Ваша компания»" />
|
<input
|
||||||
|
type="text"
|
||||||
|
id="company"
|
||||||
|
name="company"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="ООО «Ваша компания»"
|
||||||
|
defaultValue={state?.previousState?.company ? state?.previousState?.company : ''}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-row']}`}>
|
<div className={`${styles['form-row']}`}>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']} ${styles['required']}`}>Пароль</label>
|
<label className={`${styles['form-label']} ${styles['required']}`}>Пароль</label>
|
||||||
<input type="password" id="password" name="password" className={`${styles['form-input']}`} placeholder="Минимум 6 символов" />
|
<input
|
||||||
{errorMessage?.password && (
|
type="password"
|
||||||
<p className="text-sm text-red-500">{errorMessage!.password}</p>
|
id="password" name="password"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="Минимум 8 символов"
|
||||||
|
defaultValue={state?.previousState?.password ? state?.previousState?.password : ''}
|
||||||
|
/>
|
||||||
|
{state?.error?.password && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.password}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles['form-group']}`}>
|
<div className={`${styles['form-group']}`}>
|
||||||
<label className={`${styles['form-label']} ${styles['required']}`}>Подтвердите пароль</label>
|
<label className={`${styles['form-label']} ${styles['required']}`}>Подтвердите пароль</label>
|
||||||
<input type="password" id="confirm_password" name="confirm_password" className={`${styles['form-input']}`} placeholder="Повторите пароль" />
|
<input
|
||||||
{errorMessage?.confirm_password && (
|
type="password"
|
||||||
<p className="text-sm text-red-500">{errorMessage!.confirm_password}</p>
|
id="confirm_password"
|
||||||
|
name="confirm_password"
|
||||||
|
className={`${styles['form-input']}`}
|
||||||
|
placeholder="Повторите пароль"
|
||||||
|
defaultValue={state?.previousState?.confirm_password ? state?.previousState?.confirm_password : ''}
|
||||||
|
/>
|
||||||
|
{state?.error?.confirm_password && (
|
||||||
|
<p className="text-sm text-red-500">{state?.error?.confirm_password}</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user