Files
no-copy-admin-panel-frontend/src/app/ui/forms/create-staff-form.tsx
T

252 lines
5.8 KiB
TypeScript

'use client'
import styles from '@/app/styles/module/login.module.scss'
import { useActionState, useState, useRef, useEffect } from 'react';
import { createStuff } from '@/app/actions/stuffActions';
import { useTranslations } from 'next-intl';
import { IconEye } from '@/app/ui/icons/icons';
import { useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { z } from 'zod';
const createStuffSchema = z.object({
fullName: z.string()
.min(2, 'full-name-too-short')
.max(100, 'full-name-too-long')
.trim(),
email: z.string()
.email('invalid-email')
.toLowerCase()
.trim(),
password: z.string()
.min(6, 'password-too-short')
.max(50, 'password-too-long'),
})
export default function CreateStaffForm({ onSuccess }: { onSuccess?: () => void }) {
const [state, formAction, isPending] = useActionState(
createStuffAction,
undefined,
);
const t = useTranslations('Login-register-form');
const tStaff = useTranslations('Staff');
const [showPassword, setShowPassword] = useState(false);
function toggleShowPassword() {
setShowPassword(!showPassword);
}
const queryClient = useQueryClient();
useEffect(() => {
if (state?.success) {
toast.success(tStaff('staff-created-successfully'));
queryClient.invalidateQueries({ queryKey: ['stuffList'] });
if (onSuccess) {
onSuccess();
}
}
if (state?.error?.server) {
toast.error(t(state.error.server));
}
}, [state, queryClient, onSuccess, t, tStaff]);
return (
<form
className={`${styles['form-wrapper']}`}
action={formAction}
autoComplete="off"
>
{/* Поле Email */}
<div className={`${styles['form-group']}`}>
<label className={`${styles['form-label']}`}>
{t('email-adress')}
</label>
<input
type="email"
id="email"
name="email"
className={`${styles['form-input']}`}
placeholder={t('enter-email')}
defaultValue={state?.previousState?.email || ''}
autoComplete="off"
onChange={(e) => {
e.target.value = e.target.value.toLowerCase();
}}
/>
{state?.error?.email && (
<p className={`${styles['form-error']}`}>
{t(state?.error?.email)}
</p>
)}
</div>
{/* Поле Password */}
<div className={`${styles['form-group']}`}>
<label className={`${styles['form-label']}`}>
{t('password')}
</label>
<div className={`${styles['password-wrapper']}`}>
<input
type={showPassword ? "text" : "password"}
id="password"
name="password"
className={`${styles['form-input']} ${styles['password']}`}
placeholder={t('enter-password')}
autoComplete="new-password"
/>
<button
onClick={toggleShowPassword}
type="button"
className={`show-password-button ${showPassword ? 'show' : ''}`}
>
<IconEye />
</button>
</div>
{state?.error?.password && (
<p className={`${styles['form-error']}`}>
{t(state?.error?.password)}
</p>
)}
</div>
{/* Поле Full Name */}
<div className={`${styles['form-group']}`}>
<label className={`${styles['form-label']}`}>
{tStaff('full-name')}
</label>
<input
type="text"
id="fullName"
name="fullName"
className={`${styles['form-input']}`}
placeholder={tStaff('enter-full-name')}
defaultValue={state?.previousState?.fullName || ''}
autoComplete="off"
/>
{state?.error?.fullName && (
<p className={`${styles['form-error']}`}>
{t(state?.error?.fullName)}
</p>
)}
</div>
{/* Общая ошибка сервера */}
{state?.error?.server && !state.success && (
<p className={`${styles['form-error']}`}>
{t(state?.error?.server)}
</p>
)}
{/* Кнопка отправки */}
<button
type="submit"
className={`${styles['btn']}`}
disabled={isPending}
>
{tStaff('create-staff')}
{isPending && (
<div className="loading-animation">
<div className="global-spinner"></div>
</div>
)}
</button>
</form>
)
}
async function createStuffAction(
state: {
previousState: {
fullName?: string;
email?: string;
password?: string;
}
error: Record<string, string>
success?: boolean;
} | undefined,
formData: FormData,
) {
const fullName = formData.get('fullName') as string || '';
const email = formData.get('email') as string || '';
const password = formData.get('password') as string || '';
const validatedFields = createStuffSchema.safeParse({
fullName,
email,
password
});
if (!validatedFields.success) {
const errors: Record<string, string> = {}
JSON.parse(validatedFields.error.message).forEach((obj: {
message: string,
path: string[]
}) => {
const fieldName = obj.path[0];
if (errors[fieldName]) {
errors[fieldName] = `${errors[fieldName]} ${obj.message}`;
} else {
errors[fieldName] = obj.message;
}
});
return {
previousState: {
fullName,
email,
password
},
error: errors,
success: false
};
}
try {
const { fullName, email, password } = validatedFields.data;
// Вызов API для создания сотрудника
const result = await createStuff(fullName, email, password);
if (result) {
return {
previousState: {
fullName: '',
email: '',
password: ''
},
error: {},
success: true
};
} else {
throw new Error('creation-failed');
}
} catch (error) {
const errors: Record<string, string> = {}
switch (error) {
case 'email-already-exists':
errors['email'] = 'email-already-exists';
break;
case 'invalid-email':
errors['email'] = 'invalid-email';
break;
default:
errors['server'] = 'request-ended-with-an-error';
break;
}
return {
previousState: {
fullName,
email,
password
},
error: errors,
success: false
};
}
}